Verilog語法_3(同步有限狀態機)

September 21, 2016
作者:dengshuai_super
出處:http://blog.csdn.net/dengshuai_super/article/details/52571372
聲明:轉載請註明作者及出處。


同步有限狀態機的設計

1. 什麼是有限狀態機(FSM)

在FPGA裏面做有限狀態機的原因:因爲FPGA都是並行處理的,想要做一些有前後順序的事件處理的時候,我們就引入這種狀態的機制。因此狀態機在FPGA裏面應用這麼廣。
在軟件裏面也是有狀態機的思想,但是軟件它是一個順序執行的方法,所以狀態機的存在顯得不是那麼重要了。

有限狀態機是由寄存器組和組合邏輯構成的硬件時序電路;
其狀態(即由寄存器組的1和0的組合狀態所構成的有限個狀態)只能在同一時鐘跳變沿的情況下才能從一個狀態轉向另一個狀態;
究竟轉向哪一狀態不但取決於各個輸入值,還取決於當前狀態。
狀態機可用於產生在時鐘跳變沿時刻開關的複雜的控制邏輯,是數字邏輯的控制核心。


2. FSM的種類和不同點

Mealy狀態機:
這裏寫圖片描述

帶流水線輸出的Mealy狀態機:
這裏寫圖片描述


有限狀態機框圖如下:
這裏寫圖片描述
這裏寫圖片描述


3. 設計舉例

這裏寫圖片描述

根據上圖代碼實現:

//ex_fsm.v
module ex_fsm(
                input wire   sclk,
                input wire   rst_n,
                output reg   k1,//輸出的時候可以作爲寄存器,它相當於把輸出寄存器的
                output reg   k2,//Q端直接連接到輸出口了,就把中間那根線給省略了
                input  wire  A//狀態
);
parameter    IDLE   =  4'b0001;//4'h1十六進制,狀態少的時候最好顯示的寫出狀態表達式
parameter    START  =  4'b0010;
parameter    STOP   =  4'b0100;
parameter    CLEAR  =  4'b1000;

//reg  [1:0] state;
//2'b00 2'b01 2'b10 2'b11,二進制編碼的時候用的寄存器數量少,但是用的組合邏輯資源較多
//if(state == 2'b11)比較器是2比特的

reg [3:0]  state;
//4'b0001 4'b0010 4'b0100 4'b1000 獨熱碼佔用寄存器數量多,但是組合邏輯資源消耗較少
//if(state == 4'b0001)---->if(state[0]==1'b1)綜合後把4比特的比較器優化成1比特的比較器,所以佔用的組合邏輯資源較少
//對於二進制編碼(多個比特表示一個狀態),比特線有可能不一樣長,導致延遲,出現中間狀態,本來應該是111,可能中間狀態是110等,(兩邊交錯不穩定,使得數據存在不穩定區)因此在跑高速的時候可能出現數據採樣窗變小,使得建立時間、保持時間的餘量減少
//而獨熱碼就不會出現這個問題,因爲它用一個比特表示一個狀態,從出發到結束就是一根線,不會出現中間狀態,可以跑高速。

//兩段式描述狀態機
//第一段描述狀態機,(狀態機是時序邏輯)
always @(posedge sclk or negedge rst_n)//只對狀態進行處理,不會寫入其他變量賦值
                if(rst_n == 1'b0)
                        state<=IDLE;//非阻塞賦值
                else 
                        case(state)
                                    IDLE:if(A==1'b1)    
                                                    state <=START;//時序電路,不加else自動保持原狀態,因此可以不寫
                                             //else
                                                    //state <=state;
                                    START:if(A==1'b0)
                                                    state <= STOP;//復位的時候回到IDLE,最上邊的if那有相關代碼
                                    STOP:if(A==1'b1)
                                                    state <= CLEAR;
                                  CLEAR:if(A==1'b0)
                                          state <= IDLE;
                                  default:state <= IDLE;
                        endcase

//控制變量輸出
always @(posedge sclk or negedge rst_n)
                if(rst_n == 1'b0)
                                k1 <= 1'b0;
              else if(state == IDLE && A == 1'b1)
                            k1 <= 1'b0;
              else if(state == CLEAR && A == 1'b0)
                            k1 <= 1'b1;

always @(posedge sclk or negedge rst_n)
                if(rst_n == 1'b0)
                                k2 <= 1'b0;
                else if(state ==STOP && A == 1'b1)
                                k2 <= 1'b1;
                else if(state ==CLEAR && A == 1'b0)
                                k2 <= 1'b0;


endmodule
//tb_ex3_fsm.v
`timescale 1ns/1ns
module tb_ex3_fsm;
reg sclk,rst_n;
reg in_A;
wire k1,k2;
initial begin
                sclk <= 0;
                rst_n <= 0;
                #100;
                rst_n <=1;
end

initial begin
                #200;
                in_data();              
end


always #10 sclk <=~sclk;

ex_fsm ex_fsm_inst(
                .sclk         (sclk),
                .rst_n        (rst_n),
                .k1           (k1),//k1我上邊沒聲明,但是綜合的時候自動聲明一個wire變量,不推薦
                .k2           (k2),//k1,k2是輸出,芯片畫PCB時,輸出的管腳都用線連
                .A            (in_A)//狀態
);

task in_data();
            integer i;
      begin
            for(i=0;i<1024;i=i+1)
            begin
                    @(posedge sclk);
                    if(i<50)
                            in_A<=0;
                    else if(i<200)
                            in_A<=1;
                    else if(i<700)
                            in_A<=0;
                    else if(i<800)
                            in_A<=1;
                    else if(i<900)
                            in_A<=0;                
            end
      end
endtask
endmodule

在Quartus II裏面進行仿真設置後,點擊EDA Netlist Writer後
在ex3/quartus_prj 裏面多了一個Simulation文件夾,文件夾下有modelsim文件夾
該文件夾下有:
ex_fsm.sft
ex_fsm.vo//標準網標
ex_fsm_7_1200mv_125c_slow.vo//”125”指的是125度,分析建立時間,因爲只有在信號傳輸地太慢了
ex_fsm_7_1200mv_125c_slow.sdo//,路徑延時太大了的時候,纔會建立時間的違例
ex_fsm_min_1200mv_-40c_fast.vo//用於建立時間的檢查,數據傳輸的太快,使得數據太快的到達
ex_fsm_min_1200mv_-40c_v_fast.sdo//當上升沿之後,數據很快的結束了,沒有辦法保持住,因此用它來檢查保持時間
ex_fsm_modelsim.xrf
ex_fsm_v.sdo//標準延時文件

//ex_fsm.vo裏面調用了ex_fsm_v.sdo文件(initial $sdf_annotate(“ex_fsm_sdo”);)
//將ex_fsm_v.sdo放到ex_3/sim下(.sdo文件一定放到根目錄,要不然找不到,就沒有延時信息)
//將ex_fsm.vo放到ex_3/design
//仿真的時候,ex_fsm.vo裏面調用了Altera FPGA裏面的東西。因此需要加進來一些庫文件。
//庫文件在哪裏找:打開Quartus II安裝目錄下:QuartusII13.1/quartus/eda/sim_lib下把alter_mf.v拷貝到ex_3/sim目錄下的新建的文件夾altera_lib下。
打開modelsim,在Project標籤頁下把ex_fsm.v移除,加入ex_3/design/ex_fsm.vo文件
再加一個庫文件ex_3/sim/altera_lib/altera_mf.v
共三個文件:altera_mf.v,ex_fsm.vo,tb_ex_fsm.v
修改編譯順序:compile—>compile order—>altera_mf.v(調到第一個)
出現錯誤是因爲剛纔把ex_3/sim/work(庫) 刪了
因此新建一個庫,在最下方輸入命令:
vilb work

在Library 標籤頁下,找到tb_ex_fsm—>右鍵Simulate without Optimization啓動
有錯誤,需要加其它組件(cycloneive_io_obuf … not found…)
QuartusII13.1/quartus/eda/sim_libcycloneive_atoms.v加到ex_3/sim/altera_lib下,
然後在modelsim的Project標籤頁下,加入cycloneive_atoms.v
編譯
在Library標籤頁下,右鍵tb_ex_fsm啓動仿真
出現錯誤:“dffeas …not found…”
然後在QuartusII13.1/quartus/eda/sim_libaltera_primitives.v(原語)按同樣方式加入到ex_3/sim/altera_lib下,然後在modelsim的Project標籤頁下,加入altera_primitives.v
編譯,成功。
發現寄存的信號和時鐘不同不了,事件都有延時了。(後仿裏面的東西)

練習:檢測10010這個序列作爲練習,畫出狀態遷移圖。


來源:
https://ke.qq.com/user/index/index.html#cid=66019&term_id=100056181

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章