Verilog căn bản: bài 11: Finite State Machine - Thiết kế máy trạng thái

Lu ROm

Administrator
Staff member
25 Tháng bảy 2014
481
119
43
32
One piece
vimach.net
1. Giới thiệu.
- Về cơ bản một FSM bao gồm các mạch tổ hợp, tuần tự và đầu ra tổ hợp. Mạch tổ hợp được sử dụng để quyết định các trạng thái tiếp theo của FSM, mạch tuần tự được sử dụng để lưu trữ các trạng thái hiện tại của FSM. Mạch tổ hợp đầu ra: xác định tín hiệu ra của máy trạng thái phụ thuộc vào trạng thái hiện tại và tín hiệu đầu vào.
2.png

2, Cấu trúc.
-- Các loại máy trạng thái
- Máy trạng thái có nhiều loại phụ thuộc vào việc code của các bạn(mình trình bày phía dưới).Nhưng dù code theo thì máy trạng thái cũng có 2 loại cấu trúc chính là:
+ Mealy State Machine: Đầu ra của máy trạng thái phụ thuộc vào trạng thái hiện tại và tín hiệu đầu vào.
+ Moore State Machine : Đầu ra của máy trạng thái chỉ phụ thuộc vào trạng thái hiện tại, không phụ thuộc vào tín hiệu đầu vào.
Tùy vào nhu cầu mà chúng ta nên sử dụng loại Mealy hay Moore.Dù cho chúng ta dung loại thì chúng cũng có 3 thành phần cơ bản: Mạch tổ hợp xác định trạng thái kế tiếp (next state), Mạch tổ hợp xác định giá trị ngõ ra và mạch tuần tự lưu giữ trạng thái hiện tại (current state).

-- Encoding Style
- Có nhiều loại code cho máy trạng thái như mình giới thiệu ở trên. Và sau đây là một số loại code cơ bản phụ thuộc vào cách chúng ta biểu diễn trạng thái :
  • Mã hóa nhị phân: mỗi trạng thái được biểu diện trong mã nhị phân (tức là 000, 001, 010 ....).
  • Mã hóa nhị phân: mỗi trạng thái được thể hiện trong mã nhị phân (tức là 000, 001, 010 ....).
  • One Hot: chỉ có một bit là ở mức cao và phần còn lại là mức ở thấp (tức là 0001, 0010, 0100, 1000).
  • One Lạnh: chỉ có một bit là ở mức thấp, còn lại là ở mức cao (1110,1101,1011,0111).
- Sau đây mình sẽ hướng dẫn code và giải thích của từng thành phần trong FSM.

** Ở đây mình sẽ ví dụ bộ đếm lên, xuống và dừng khi nhấn nút trong máy trạng thái.

-- Cho tý hình nhỉ:

hi.png


-- Về cơ bản, chúng ta sẽ có các tín hiệu sau: tín hiệu vào( mình chọn nút nhấn), xung clk, tín hiệu reset và tín hiệu ra.
-- Trong đó:
  • clock: là xung nhịp đồng bộ của FSM.
  • reset: là tín hiệu reset FSM sau khi mới bật nguồn để FSM vào trạng thái khởi động. Reset đồng bộ tích cực mức cao.
  • Tín hiệu vào: một trong 3 nút nhấn điều khiển lên, xuống, dừng.
  • Tín hiệu ra: ngõ ra của bộ phát hiện (ngõ ra FSM). Trạng thái mặc định sẽ là đếm lên, sau đó tùy vào tín hiệu vào mà chúng ta cho đếm lên xuống hoặc dừng.
-- Mạch chính cho máy trạng thái:
demc.png

- Trong đó ta có 3 trạng thái chính là đếm lên, lùi và dừng cùng với biểu diễn lần lượt nhị phân là 001, 010,100. Trạng thái 000 mình sẽ mặc định là đếm lên. Chú ý: mình sử dụng loại Moore nha.
- Phân tích:
** Ở trạng thái hiện tại là tiến ( màu đỏ bên trong hình elip, có 3 mũi tên đi ra tương đương với 3 tín hiệu điều khiển đến trạng thái tiếp theo) biểu diễn nhị phân là 001:
o Nếu tín hiệu điều khiển là lùi ( màu đỏ, tương đương với chúng ta nhấn nút 1) thì trạng thái tiếp theo sẽ là trạng thái lui ( biểu diễn nhị phân là 010) cũng là tín hiệu ra output.
o Ngược lại tín hiệu điều khiển là dừng ( tương đương với nhấn nút 2) thì trạng thái tiếp theo sẽ là dừng ( biểu diễn nhị phân là 100) cũng là tín hiệu ra output.
o Còn tín hiệu điều khiển tiến thì trạng thái tiếp theo là tiến.

** Tương tự với trạng thái hiện tại là dừng, lùi: chúng ta cũng có 3 tín hiệu điều khiển và ba trạng thái tiếp theo tùy thuộc vào ba tín hiệu điều khiển đó.
** Sau đây là phần code từng phần:
4.png

++ Đoạn code cho “Mạch tổ hợp xác định trạng thái kế tiếp”: ( vòng tròn 1)

Mã:
always @(*)
          
            begin
              
                case (state_current)
                  
                    2'b00    :      
                                begin
                                  
                                    if            (nut_t1 ==    1'b1)
                                                  
                                                    state_next        =        2'b01;
                                  
                                    else if    (nut_t2 == 1'b1)
                                                  
                                                    state_next        =        2'b10;
                                  
                                    else if    (nut_t3    ==    1'b1)
                                                  
                                                    state_next        =        2'b00;  
                                    else
                                                  
                                                    state_next        =        2'b00;
                                      
                                end          
                    2'b01:
                                begin
                                    if            (nut_t2    ==    1'b1)
                                                  
                                                    state_next        =        2'b10;
                                                  
                                    else if    (nut_t3    ==    1'b1)
                                  
                                                    state_next        =        2'b00;
                                                  
                                    else if    (nut_t1    ==    1'b1)
                                                  
                                                    state_next        =        2'b01;
                                                  
                                    else
                                                    state_next        =        2'b01;
                                                  
                                end
                              
                    2'b10:  
                                begin
                                        if            (nut_t3    ==    1'b1)
                                      
                                                    state_next        =        2'b00;
                                          
                                        else if (nut_t1    ==    1'b1)
                                      
                                                    state_next        =        2'b01;
                                          
                                        else if(nut_t2    ==    1'b1)
                                      
                                                    state_next        =        2'b10;
                                          
                                        else
                                                    state_next        =        2'b10;
                                                  
                                end
                    default                        state_next        =        2'b00;
            endcase
        end
++ Đoạn code cho mạch tuần tự ( chữ nhật 2):
Mã:
always @ (posedge clk, posedge reset )
            begin
              
                if(reset)
                        state_current      <=         2'b00;
                else
                        state_current        <=            state_next;
                  
            end
++ Đoạn code cho đầu ra ( ô vuông 3):
Mã:
always @(*)
                begin
                    case    (    state_current )
                  
                  
                        2'b00:                    {R3,R2,R1}        =        3'b001;
                      
                        2'b01:                    {R3,R2,R1}        =        3'b010;
                      
                        2'b10:                    {R3,R2,R1}        =        3'b100;
                      
                        default                    {R3,R2,R1}        =        3'b000;
                  
                    endcase
                end

// Ở đây mình dùng các tín hiệu R3, R2, R1 để quay lại điều khiển một đoạn code khác. Các bạn xem chương trình chính sẽ hiểu. Nếu không hiểu thic cmt ở dưới mình sẽ trả lời.
++ Đoạn code cho toàn bộ bài:
Mã:
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date:    08:53:39 11/03/2014
// Design Name:     PHẠM KIM LUÂN
// Module Name:    nut3
// Project Name:  DEM LEN XUONG, DUNG
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module DEM( 
                                    clk,
                                    reset,
                                    nut1_l,
                                    nut2_d,
                                    nut3_t,
                                    Q
                );

    //input
   
    input                             clk;
    input                             reset;
    input                             nut1_l;
    input                             nut2_d;
    input                             nut3_t;
   
    //output
    output                             Q;
   
    wire                             Rs;
    wire                            nut_t3;
    wire                            nut_t2;
    wire                            nut_t1;
   
   
    reg                                R1;
    reg                             R2;
    reg                             R3;
    reg            [1:0]                state_next;
    reg            [1:0]                state_current;
    reg         [28:0]                Qs;
    reg         [3:0]                Q;
    reg                                nut_1;
    reg                                nut_2;
    reg                                nut_3;
   
        // tao xung 1S
        always @ (posedge clk)
            begin
                                    if (Rs)
                                        Qs    <=    29'd0;
                                    else
                                        Qs    <=    Qs + 29'd1;
            end
   
        assign               Rs         =       (Qs == 29'd50000000)     ?         1'b1         :         1'b0;
   
        // bo dem 3 nut nhan
        always @ (posedge clk,
                    posedge reset)
            begin
                                    if(reset)
                                        Q         <=        4'd0;
                                    else
                                        begin
                                            if( ~Rs )
                                                Q                <=            Q;
                                               
                                            else
                                                begin
                                                    case ({R3,R2,R1})
                                                   
                                                        3'b000        :             Q        <=         Q + 4'd1;    // DEM LEN
                                                   
                                                        3'b001        :             Q        <=         Q + 4'd1;   //DEM LEM
                                                   
                                                        3'b010        :             Q        <=         Q - 4'd1;   //DEM XUONG
                                                   
                                                        3'b100        :             Q        <=         Q ;     //DUNG
                                                   
                                                        default        :            Q        <=            4'd0;
                                                   
                                                endcase
                                               
                                            end
                                        end
            end
       
        always @ (posedge clk, posedge reset )
            begin
               
                if(reset)
                        state_current      <=         2'b00;
                else
                        state_current        <=            state_next;
                   
            end
       
        always @(*)
           
            begin
               
                case (state_current)
                   
                    2'b00    :       
                                begin
                                   
                                    if            (nut_t1 ==    1'b1)
                                                   
                                                    state_next        =        2'b01;
                                   
                                    else if    (nut_t2 == 1'b1)
                                                   
                                                    state_next        =        2'b10;
                                   
                                    else if    (nut_t3    ==    1'b1)
                                                   
                                                    state_next        =        2'b00;   
                                    else
                                                   
                                                    state_next        =        2'b00;
                                       
                                end           
                    2'b01:
                                begin
                                    if            (nut_t2    ==    1'b1)
                                                   
                                                    state_next        =        2'b10;
                                                   
                                    else if    (nut_t3    ==    1'b1)
                                   
                                                    state_next        =        2'b00;
                                                   
                                    else if    (nut_t1    ==    1'b1)
                                                   
                                                    state_next        =        2'b01;
                                                   
                                    else
                                                    state_next        =        2'b01;
                                                   
                                end
                               
                    2'b10:   
                                begin
                                        if            (nut_t3    ==    1'b1)
                                       
                                                    state_next        =        2'b00;
                                           
                                        else if (nut_t1    ==    1'b1)
                                       
                                                    state_next        =        2'b01;
                                           
                                        else if(nut_t2    ==    1'b1)
                                       
                                                    state_next        =        2'b10;
                                           
                                        else
                                                    state_next        =        2'b10;
                                                   
                                end
                    default                        state_next        =        2'b00;
            endcase
        end
        always @(*)
                begin
                    case    (    state_current )
                   
                   
                        2'b00:                    {R3,R2,R1}        =        3'b001;
                       
                        2'b01:                    {R3,R2,R1}        =        3'b010;
                       
                        2'b10:                    {R3,R2,R1}        =        3'b100;
                       
                        default                    {R3,R2,R1}        =        3'b000;
                   
                    endcase
                end   
       
       //  CẮT NGẮN MƯC CAO CỦA NUT NHẤN ĐỂ VỪA ĐỦ MỘT CHU KÌ XUNG CLK.
always @ (posedge clk)
            begin
                nut_1         <=                     nut1_l;
            end
       
        assign    nut_t1    =                    (~nut_1)                    &            nut1_l;
       
        always @ (posedge clk)
            begin
                    nut_2            <=                 nut2_d;
            end
       
        assign    nut_t2        =                (~nut_2)                &                nut2_d;

        always @    (posedge clk)
            begin
                    nut_3            <=                 nut3_t;
            end
       
        assign    nut_t3        =                (~nut_3)                &                nut3_t;
       
endmodule
Khuyến mãi thêm video cho hấp dẫn :v
minion_bigminion_big