2013年9月23日

FPGA Verilog 執行、編譯、撰寫 多工器

撰寫與執行程式步驟

增值表=>卡諾圖畫簡=>邏輯運算式(閘級寫法)=>行為描述(高階寫法)
增值表=>撰寫程式碼

---------------- 範例 2對4解碼器 --------------------

增值表:


a
b
I3
I2
I1
I0
0
0
0
0
0
1
0
1
0
0
1
0
1
0
0
1
0
0
1
1
1
0
0
0

卡諾圖畫簡:




y1 y2 y3 省略

 











邏輯運算式:

y0=a'&b'
y1=a&b'
y2=a'&b
y3=a&b

行為描述:

詳細語法請先見課本p.2-3~p.3-15,再撰寫程式碼

--------------------初步解釋-----------------------
y0=a、b皆為0時      => assign y[0]=({b,a}==2'd0);  //假設b為高位元,則放左邊{b,a}
y1=a為1、b為0時    => assign y[1]=({b,a}==2'd1);
y2=a為0、b為1時    => assign y[2]=({b,a}==2'd2);
y3=a、b皆為1時      => assign y[3]=({b,a}==2'd3);

假設a、b皆為一位元

將其合併成兩位元=>y=({b,a}==2'b00);   a、b合成成為兩位元且其值為00
其中 b=>二進制 d=>十進制 o=>八進制 h=>十六進制
         2'代表位元長度為兩位元
         詳細請看課本2-6頁
---------------------------------------------------------------------------
test bench 測試平台 =>亦為一個模組

將待測模組加入
測試訊號(stimulus或test vectors)以及除錯訊號($display或$dumpvars)

所組成之模組其架構如下:
module 測試平台名稱;
宣告測試訊號
reg 測試訊號變數名;(待測模組之輸入訊號)
wire 測試訊號變數名;(待測模組織輸出訊號)

使用begin end會執行begin end內部的程式碼(相當於c語言的{})
begin
xxxxx
xxxxx
end

input改reg
output改wire

在initial內之時間延遲為相對的非絕對的
    #0 a=0; ->t=0
    #10 a=1; ->t=0+10
    #10 a=0;  ->t=10+10   絕對的話->t=10


----儲存模擬資料之指令----
$dumpfile("儲存資料檔名");//ex:$dumpfile("xxx.vcd");儲存為可看波形的.vcd檔
$dumpvars;

其副檔名為=> .vcd
------------------------------------------------------
設計檔案分為=>設計本體、設計測試

需要將上述指令放在測試平台(模擬)之initial方塊內
如下:
initial
  begin
    $dumpfile("test.vcd");
    $dumpvars;
  end

程式碼撰寫:

------------------檔名存為test.v-------------------
module deco2_4(a,b,y);
        input a,b;
        output [3:0] y;  //input、output輸出入變數個數要與第一行模組宣告的輸出入變數個數一致

        assign y[0]=({a,b}==2'd0);
        assign y[1]=({a,b}==2'd1);
        assign y[2]=({a,b}==2'd2);
        assign y[3]=({a,b}==2'd3);
endmodule


-------------檔名存為testexample.v----------------
`timescale 1ns/100ps
`include"example.v"

module testdeco;
        reg a,b;
        wire [3:0] y;

        deco2_4 U1(a,b,y);//對應example.v檔案內第一行的module宣告

        integer i;
        initial
        begin
                for(i=0;i<=4;i=i+1)
                begin
                        {a,b}=i;
                        #10;
                end
        end

        initial
        begin
                $dumpfile("test.vcd");
                $dumpvars;
        end
endmodule
-------------GTKWAVE 模擬波形圖--------------


開始執行

---- 環境變數設定(無法執行時在看環境變數設定,請先看下面的iverilog、gtkwave步驟)-------





----執行iverilog、gtkwave----


step1.開啟命令列後,先輸入iverilog測試是否有安裝成功,成功的話即出現如下


       如果你沒有出現此訊息,而是出現"不是內部或外部命令",可能你打錯字或環境變數無自動設定,請回到最上面的步驟----環境變數設定----,操作此步驟在回過來測試


      step2.安裝成功後,請先把你的程式碼檔案都建立好,並確定你的檔案所存放的位置在哪,
假設你檔案存在桌面,則我們用cd指令進入Desktop桌面,在鍵入下面編譯ivrilog指令

       iverilog 所要編譯的檔名.v -o 編譯後的輸出檔名(任意取名)
打完後按Enter如果都沒出現任何訊息表示編譯成功。

若有錯誤訊息如下:

     由圖中可得知testexample.v這檔案的第13行,程式碼有誤

      step3.vvp 編譯後的輸出檔名(請注意此必須更上面的輸出檔名一致)
      如果成功的話則會告訴你他輸出一個  xxx.vcd 檔 
       VCD info: dumpfile test.vcd opened for output
       gtkwave test.vcd   模擬波形



如果出現此視窗表示成功



-----------------------------------------------------------------
撰寫程式步驟
畫增值表=>卡若圖畫簡=>閘級寫法=>高階寫法
見課本 範例 4-3 為閘級寫法
底下同為 範例4-3 為高階寫法
----------------範例4-3 高階寫法----------------------
//XOR真值表   奇1為1
//  a  b  y
//  0  0  0
//  0  1  1
//  1  0  1
//  1  1  0
//符號~為反向之意義,符號^為XOR之意義
//a=b之邏輯 =>~a^b
//以verilog來設計一位元比較器
module comp1(a,b,aeqb,altb,agtb);
input a,b;//一位元比較器
output aeqb,altb,agtb;
assign #1 aeqb = (a==b);//等同於~a^b
assign #1 altb = (a<b);//等同於
assign #1 agtb = (a>b);//
endmodule
//存為comp1.v
//以上為設計本體

----------- 一位元比較器之測試模組測試檔案 ------------
`timescale 1ns/100ps
`include "comp1.v"
module test_comp1;//一位元比較器之測試模組宣告
reg a,b;//input改為reg
wire aeqb,altb,agtb;//output改為wire

//實體化comp1將訊號a,b,aeqb,altb,agtb實際輸入到comp1才能產生出正確的波形(注意此comp1之名稱要與檔案comp1.v內的module名稱一致)
comp1 U1(a,b,aeqb,altb,agtb);//從左至右按照對應的順序,順序不能改變 只能改名稱

always@(a or b or aeqb or altb or agtb)//always是一個時間點,當always()括弧內的變數值改變時,就執行下列程式碼
$display("%d ns:a=%b,b=%b,aeqb=%b,altb=%b,agtb=%b",$time,a,b,aeqb,altb,agtb);//ns為奈米秒,:為字元,a=%b使a以二進制顯示

initial
  begin
    $dumpfile("testComp1.vcd");
    $dumpvars;
  end

//輸入波形
initial
  begin
    #0 a=0;b=0;
    #10 b=1;
    #10 a=1;b=0;
    #10 b=1;
    #10 a=0;b=0;
    #10 $finish;
  end

endmodule//存為test_comp1.v
//以上為設計測試模組
-------------------------------------------------------------------------
模擬:在命令提示字元下輸入
iverilog test_comp1.v -o test.comp1out
vvp test.comp1out//用vvp執行結果 test.comp1out
gtkwave testComp1.vcd//用gtkwave模擬波形

結果:



======================================================================
always@(感測列sensitive list)
  begin
    運算式1;
    運算式2;
         .
         .
  end

當感測列內之訊號有變化時,會執行運算式1、運算式2.....
感測列之語法有二
  1.訊號1 or 訊號2 or ...... 訊號n
     (變數)     (變數)
  2.posedge/negedge  時脈訊號 <or posedge/negedge 重置訊號>  end
                                                              可省略

always #延遲時間 運算式;
每延遲時間之間隔即執行一次運算式
ex
always #10 clk=~clk;
initial
#0 clk=0;

波形如下:


輸出=輸入  等號左邊叫輸出,等號右邊叫輸入
ex1:
reg c;//在always方塊內之運算式輸出須宣告為reg,在initial內之變數必須為reg之料型態
always@(a or b)//當a b值改變時就直行下列程式碼
  c=a&b;
ex2:
wire c;
assign #1 c=a&b;

result : ex1=ex2

ex3://ex3不等於ex2,ex1  ex3為栓鎖??
reg c;
always@(a)
c=a&b;

========================================================================
多工器(Multipexer)(多對一)

二對一多工器 to 4-19

若多工器之選擇訊號s則s=1時輸出為b,s=0時輸出為a,則高階寫法為
y=a?(s=1知訊號):(s=0知訊號); =>多工器輸出=選擇訊號?選擇序號=1之輸出:選擇訊號=0之輸出
         ↑
 選擇訊號

case語法類似C語言的swich
case(s)
  2'd0: y=I0;//當s=0時y=I0
  2'd1: y=I1;//當s=1時y=I1



========================================================================
請使用verilog語法寫出21多工器,並測試出波形結果。

----------------- mux2_1.v -----------------
//mux.v
module mux2_1(a,b,s,y);
input a,b,s;
output y;
assign #0 y=s?b:a;
endmodule
-----------------------------------------------

---------------test_mux2_1.v--------------
// mux2_1.v的測試平台
`timescale 1ns/100ps
`include "mux.v"
module test_mux;
reg a,b,s;
wire y;
mux2_1 U1(a,b,s,y);//實體化

initial
begin
#0 a=0;b=0;s=1;
#10 b=1;
#10 a=1;b=0;s=0;
#10 b=1;
#10 a=0;b=0;
#10 $finish;
end

initial
begin
$dumpfile("testmux.vcd");
$dumpvars;
end
endmodule
//存為test_mux2_1.v
----------------------------------------------


-------------GTKWAVE 模擬波形圖--------------



請使用verilog語法寫出31多工器,並測試出波形結果。

----------------- mux3_1.v -----------------
//mux3_1.v
module mux3_1(a,b,c,s,t,y);
input a,b,c,s,t;
output y;
/*
wire o;
assign #0 o=s?b:a;
assign #0 y=t?c:o;
*/

assign #0 y=t?c:
                  s?b:a;

endmodule
-----------------------------------------------

---------------test_mux3_1.v--------------
//mux3_1.v的測試平台
`timescale 1ns/100ps
`include "mux3_1.v"

module test_mux3_1;
reg a,b,c,s,t;
wire y;

mux3_1 U1(a,b,c,s,t,y);

initial
begin
#0 a=1;b=0;c=0;s=0;t=0;
#10 a=0;s=1;
#10 c=1;s=0;t=1;
#10 s=1;
#10 a=0;b=1;c=1;s=0;t=0;
#10 a=1;s=1;
#10 c=0;s=0;t=1;
#10 s=1;
#10 $finish;
end

initial
begin
$dumpfile("testMux3_1.vcd");
$dumpvars;
end

endmodule
//存為test_mux3_1.v
---------------------------------------

-------------GTKWAVE 模擬波形圖--------------


請使用verilog語法寫出41多工器,並測試出波形結果。
--------------------------------------------------------------------------------
module mux4_1(I0,I1,I2,I3,S0,S1,y);
input I0,I1,I2,I3,S0,S1;
output y;
wire [1:0] S={S1,S0};
reg y;
always @(I0 or I1 or I2 or I3 or S)
  case(S)
    2'd0: y=I0;
    2'd1: y=I1;
    2'd2: y=I2;
    2'd3: y=I3;
  endcase
endmodule
//存為mux4_1.v
---------------------------------------------------------------------------------
//mux4_1.v的測試平台
`timescale 1ns/100ps
`include "mux4_1.v"

module test_mux4_1;
reg I0,I1,I2,I3,S0,S1;
wire y;

mux4_1 U1(I0,I1,I2,I3,S0,S1,y);

integer i;//i為32位元的整數
initial begin
for(i=0;i<20;i=i+1)//讓其四位元的值依序=1.2.3......當{I3,I2,I1,I0}=2時,其值分別為0010
begin
{I3,I2,I1,I0}=i;//32位元的整數取四個位元,最左邊的為高位元
#10;//純延遲
end
end

initial begin
#0 S0=0;S1=0;
#40 S0=1;
#40 S0=0;S1=1;
#40 S0=1;
#40 S0=0;S1=0;
#40 $finish;
end

initial
begin
$dumpfile("testMux.vcd");
$dumpvars;
end
-------------------------------------------------------------------------------------------------
波形結果:


========================================================================

$display與$monitor之差異

                   .
                   .
                   .
initial
begin
$display("%d ns:a=%b,b=%b,aeqb=%b,altb=%b,agtb=%b",$time,a,b,aeqb,altb,agtb);
end
                  .
                  .

結果:


                   .
                   .
                   .
initial
begin
$monitor("%d ns:a=%b,b=%b,aeqb=%b,altb=%b,agtb=%b",$time,a,b,aeqb,altb,agtb);
end
                  .
                  .
結果:


$monitor會持續偵測變數,當變數值改變即會顯示,沒有特定的時間。

5 則留言:

文章有誤或有問題麻煩您留言告知! 謝謝您~~