状态机设计:3 段式(推荐)
状态机设计如下:
 (0) 首先,根据状态机的个数确定状态机编码。利用编码给状态寄存器赋值,代码可读性更好。
 (1) 状态机第一段,时序逻辑,非阻塞赋值,传递寄存器的状态。
 (2) 状态机第二段,组合逻辑,阻塞赋值,根据当前状态和当前输入,确定下一个状态机的状态。
 (3) 状态机第三代,时序逻辑,非阻塞赋值,因为是 Mealy 型状态机,根据当前状态和当前输入,确定输出信号。
// vending-machine
// 2 yuan for a bottle of drink
// only 2 coins supported: 5 jiao and 1 yuan
// finish the function of selling and changingmodule  vending_machine_p3  (input           clk ,input           rstn ,input [1:0]     coin ,     //01 for 0.5 jiao, 10 for 1 yuanoutput [1:0]    change ,output          sell    //output the drink);//machine state decodeparameter            IDLE   = 3'd0 ;parameter            GET05  = 3'd1 ;parameter            GET10  = 3'd2 ;parameter            GET15  = 3'd3 ;//machine variablereg [2:0]            st_next ;reg [2:0]            st_cur ;//(1) state transferalways @(posedge clk or negedge rstn) beginif (!rstn) beginst_cur      <= 'b0 ;endelse beginst_cur      <= st_next ;endend//(2) state switch, using block assignment for combination-logic//all case items need to be displayed completely    always @(*) begin //st_next = st_cur ;//如果条件选项考虑不全,可以赋初值消除latchcase(st_cur)IDLE:case (coin)2'b01:     st_next = GET05 ;2'b10:     st_next = GET10 ;default:   st_next = IDLE ;endcaseGET05:case (coin)2'b01:     st_next = GET10 ;2'b10:     st_next = GET15 ;default:   st_next = GET05 ;endcaseGET10:case (coin)2'b01:     st_next = GET15 ;2'b10:     st_next = IDLE ;default:   st_next = GET10 ;endcaseGET15:case (coin)2'b01,2'b10:st_next = IDLE ;default:   st_next = GET15 ;endcasedefault:    st_next = IDLE ;endcaseend//(3) output logic, using non-block assignmentreg  [1:0]   change_r ;reg          sell_r ;always @(posedge clk or negedge rstn) beginif (!rstn) beginchange_r       <= 2'b0 ;sell_r         <= 1'b0 ;endelse if ((st_cur == GET15 && coin ==2'h1)|| (st_cur == GET10 && coin ==2'd2)) beginchange_r       <= 2'b0 ;sell_r         <= 1'b1 ;endelse if (st_cur == GET15 && coin == 2'h2) beginchange_r       <= 2'b1 ;sell_r         <= 1'b1 ;endelse beginchange_r       <= 2'b0 ;sell_r         <= 1'b0 ;endendassign       sell    = sell_r ;assign       change  = change_r ;endmodule
状态机修改:2 段式
将 3 段式状态机 2、3 段描述合并,其他部分保持不变,状态机就变成了 2 段式描述。
 修改部分如下:
//(2) state switch, and output logic
//all using block assignment for combination-logic
reg  [1:0]   change_r ;
reg          sell_r ;
always @(*) begin //all case items need to be displayed completelycase(st_cur)IDLE: beginchange_r     = 2'b0 ;sell_r       = 1'b0 ;case (coin)2'b01:     st_next = GET05 ;2'b10:     st_next = GET10 ;default:   st_next = IDLE ;endcase // case (coin)endGET05: beginchange_r     = 2'b0 ;sell_r       = 1'b0 ;case (coin)2'b01:     st_next = GET10 ;2'b10:     st_next = GET15 ;default:   st_next = GET05 ;endcase // case (coin)endGET10:case (coin)2'b01:     beginst_next      = GET15 ;change_r     = 2'b0 ;sell_r       = 1'b0 ;end2'b10:     beginst_next      = IDLE ;change_r     = 2'b0 ;sell_r       = 1'b1 ;enddefault:   beginst_next      = GET10 ;change_r     = 2'b0 ;sell_r       = 1'b0 ;endendcase // case (coin)GET15:case (coin)2'b01: beginst_next     = IDLE ;change_r    = 2'b0 ;sell_r      = 1'b1 ;end2'b10:     beginst_next     = IDLE ;change_r    = 2'b1 ;sell_r      = 1'b1 ;enddefault:   beginst_next     = GET15 ;change_r    = 2'b0 ;sell_r      = 1'b0 ;endendcasedefault:  beginst_next     = IDLE ;change_r    = 2'b0 ;sell_r      = 1'b0 ;endendcase
end
状态机修改:1 段式(慎用)
将 3 段式状态机 1、 2、3 段描述合并,状态机就变成了 1 段式描述。
 修改部分如下:
//(1) using one state-variable do describereg  [1:0]   change_r ;reg          sell_r ;always @(posedge clk or negedge rstn) beginif (!rstn) beginst_cur     <= 'b0 ;change_r   <= 2'b0 ;sell_r     <= 1'b0 ;endelse begincase(st_cur)IDLE: beginchange_r  <= 2'b0 ;sell_r    <= 1'b0 ;case (coin)2'b01:     st_cur <= GET05 ;2'b10:     st_cur <= GET10 ;endcaseendGET05: begincase (coin)2'b01:     st_cur <= GET10 ;2'b10:     st_cur <= GET15 ;endcaseendGET10:case (coin)2'b01:     st_cur   <=  GET15 ;2'b10:     beginst_cur   <= IDLE ;sell_r   <= 1'b1 ;endendcaseGET15:case (coin)2'b01:     beginst_cur   <= IDLE ;sell_r   <= 1'b1 ;end2'b10:     beginst_cur   <= IDLE ;change_r <= 2'b1 ;sell_r   <= 1'b1 ;endendcasedefault:  beginst_cur    <= IDLE ;endendcase // case (st_cur)end // else: !if(!rstn)end