Verilog_有限状态机

版权声明:欢迎读者提问交流。 个人水平有限,表述不当或疏漏之处敬请批评指正。 作者:仼先生 来源:CSDN 著作权归作者所有。非商业转载请注明出处,商业转载请联系作者获得授权。 https://blog.csdn.net/qq_41394155/article/details/83958639

名词解释

状态机就是一种能够描述具有逻辑顺序和时序顺序事件的方法。

状态机有两大类:Mealy型和Moore型。
Moore型状态机的输出只与当前状态有关,而Mealy型状态机的输出不仅取决于当前状态,还受到输入的直接控制,并且可能与状态无关。

当使用Verilog来描述一个简单状态机的设计时,应将状态寄存器的控制器的控制和状态机状态里的组合逻辑分开。

代码风格

一段式

当前状态、下一状态、当前输出值都写在一个always块中

二段式

当前状态、下一状态、当前输出值写在两个always块中

  • 注意:这样三种组合方式,及有三种方式写这两个always块。

三段式

当前状态、下一状态、当前输出值分别写在各自的always块中,这样需要3个always块。

自动售报机Verilog实现


设计说明

设计一个简单的数字电路用于电子的报纸售卖机的投币器。

design code 

  • 假设报纸的价格为15分。
  • 投币器只能接受5分和1角的硬币。
  • 必须提供适当的数目的零钱,投币器不找零。
  • 合法的硬币组合包括1个5分的硬币和1个一角的硬币,3个5分的硬币,1个1角的硬币和1个5分的硬币。2个1角的硬币是合法的,但是投币器不找零。
module vend(
            input    [1:0]   coin,
            input            clock,
            input            reset,
            output           newspaper
            );

//声明有限状态机的内部状态
wire    [1:0]   NEXT_STATE;
reg     [1:0]   PRES_STATE;

//状态编码
parameter     s0  = 2'b00;
parameter     s5  = 2'b01;
parameter     s10 = 2'b10;
parameter     s15 = 2'b11;

//用同步复位、时钟正跳变沿触发的状态触发器
always@(posedge clock)
begin
    if(reset == 1'b1)
        PRES_STATE <= s0;
    else
        PRES_STATE <= NEXT_STATE;
end

//组合逻辑
function [2:0] fsm;  //状态变化及输出组合逻辑
    input  [1:0]  fsm_coin;
    input  [1:0]  fsm_PRES_STATE;

    reg           fsm_newspaper;
    reg    [1:0]  fsm_NEXT_STATE;

    begin
        case(fsm_PRES_STATE)
            s0:     //状态为s0
               begin
                   if(fsm_coin == 2'b10)
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s10;
                   end
                   else if(fsm_coin == 2'b01)
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s5;
                   end
                   else
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s0;
                   end
               end
            s5:     //状态为s5
               begin
                   if(fsm_coin == 2'b10)
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s15;
                   end
                   else if(fsm_coin == 2'b01)
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s10;
                   end
                   else
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s5;
                   end
               end
            s10:     //状态为s10
               begin
                   if(fsm_coin == 2'b10)
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s15;
                   end
                   else if(fsm_coin == 2'b01)
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s15;
                   end
                   else
                   begin
                       fsm_newspaper   = 1'b0;
                       fsm_NEXT_STATE  = s10;
                   end
               end
            s15:     //状态为s15
               begin
                   fsm_newspaper   = 1'b1;
                   fsm_NEXT_STATE  = s0;
               end
           endcase

           fsm = {fsm_newspaper,fsm_NEXT_STATE};
    end
endfunction

//每当硬币放入或当前状态改变时,组合逻辑动作
assign  {newspaper,NEXT_STATE} = fsm(coin,PRES_STATE);

endmodule

 testbench

module vend_tb;

reg           clock;
reg           reset;
reg   [1:0]   coin;
wire          newspaper;

always #20 clock = ~clock;

initial
begin
    clock = 0;
    reset = 1;
    #100;
    reset = 0;

    @(posedge clock) coin[1:0] = 2'b00;
    @(posedge clock);
    @(posedge clock) coin[1:0] = 2'b01;
    @(posedge clock);
    @(posedge clock) coin[1:0] = 2'b10;
    @(posedge clock);

    @(posedge clock) coin[1:0] = 2'b10;
    @(posedge clock);
    @(posedge clock) coin[1:0] = 2'b10;
    @(posedge clock);
    
    @(posedge clock) coin[1:0] = 2'b00;
    @(posedge clock);
    @(posedge clock) coin[1:0] = 2'b01;
    @(posedge clock);
    @(posedge clock) coin[1:0] = 2'b01;
    @(posedge clock);
    @(posedge clock) coin[1:0] = 2'b01;

    #200 $finish;
end

initial begin
  $fsdbDumpfile("test.fsdb");
  $fsdbDumpvars();
end

vend u_vend( 
            .coin(coin),
            .clock(clock),
            .reset(reset),
            .newspaper(newspaper)
             );

endmodule

猜你喜欢

转载自blog.csdn.net/qq_41394155/article/details/83958639