顯示具有 FPGA 標籤的文章。 顯示所有文章
顯示具有 FPGA 標籤的文章。 顯示所有文章

2013年3月25日 星期一

fpga 0325 講義


1. 雙向埠的原理及設計
   hw4 -> (VLSI 的 hw8a)
   bufif0 bufif1

2. 四(N)顆並聯的七段顯示器如何驅動 ?

   a. 先將腳位如何驅動七段顯示器量測出來,使用三用電表,切換至二極體模式,然後將腳位列表出來。
   b. 使用掃瞄方式撰寫 verilog code。
          ^^^^

什麼叫掃瞄 ?

假設我們要在四顆並聯的七段顯示器顯示 1234,我們會遇上一個問題是 a0~a3, b0~b3 .. h0~h3 全部都短路在一起,最主要的原因是為了節省腳位,在這種情況之下顯示會變成:

1111
2222
3333
4444
5555
..
依此類推。

如果要顯示 1234 的話,那麼我們要使用掃瞄的技巧,也就是一次點亮一顆七段顯示器,
例如:

1 -> d0 打開
2 -> d1 打開
3 -> d2 打開
4 -> d3 打開

其畫面如
http://www.youtube.com/watch?v=qxGxtjlfhTE
所示。

當掃瞄的速度很快(24 frames/sec)的時候,我們的眼睛會因為視覺暫留的原理誤以為全
部的七段顯示器都是「同時」點亮的。所謂的很快是指每秒有 24 張以上的動畫,以
1 kHz 的掃瞄速度來說,有四個字元,因此每個字元平均一秒掃 250 次,相當足夠。

3. FPGA 常見 I/O 為何 ?

   a. 輸入 - jumper、dip switch、button、keypad
   b. 輸出 - 七段顯示器、LED、矩陣 LED、LCD、VGA
   c. 雙向埠 - Memory

2013年3月18日 星期一

fpga 0318 講義


作業 3.
  請寫出 VLSI 作業 2 正緣觸發之 D 正反器,要寫以下版本:

a. gate level 版                檔名:dff_gate.v,gate level 版必須使用 XCircuit 畫出正緣觸發 D 正反器之電路圖。
b. rtl level 版 (alway @)       檔名:dff_rtl.v

請撰寫可自我偵測錯誤之 testfixture,並且適用於上述兩個不同版本之 DFF 電路,其輸出為 test_dff.dmp,檔名為 test_dff.v。

p2-6
數字表示:

 8'hec          ->  8'h 指有 8個位元 hex 數字,其值為 ec
16'd2048        -> 16'd 指有16個位元 digital 數字,其值為 2048
  o -> 八進位、b-> 二進元

24'b111111111111111111111111 = 24'b1111_1111_1111_1111_1111_1111


x -> unknown
z -> 高阻抗

# 10 test ok
# 20 test ok
# 30 test fail

p2-11

表 2-2 關鍵字,關鍵字的重要性在於我們不能拿關鍵字來當變數。例如以下寫法很糟糕:

reg if;

因為 if 為關鍵字,使用 if 當變數會有問題。


P3-7

範例 3-3

assign mount = s ? ma : mb;

if s = 1 mount = ma;
if s = 0 mount = mb;

P3-15

assign dbus = (enable == 1) ?  value1: 4'bz;

http://www.cse.psu.edu/~cg577/DOCUMENTS/codingstandards/verilog.html

儘量不要使用巢狀 ? : 來寫程式,以免看不懂,如上述網頁之例子。


P3-9 資料型態

1. 數值 0 1 x z

2. 連接線

3. 暫存器

4. 向量 ?

reg [7:0] a; -> a7a6a5a4a3a2a1a0
                27            s0
reg [0:7] b; -> a0a1 ........ a7

a 跟 b 有何不同 ? (大印地安 V.S. 小印地安)
http://www.prudentman.idv.tw/2007/11/big-endianlittle-endian.html

5. 數字 -> 無號數

6. 參數 -> 有限狀態機

7. 陣列、記憶體 -> 本學期沒有用到

8. 三態 -> 雙向埠

2013年3月11日 星期一

fpga 0311 講義


$display 語法 (課本 p2-10 - p2-12)

$display("Hello world")

可以在螢幕上顯示 Hello world 字串,在半加器的測試檔中作以下修改:

initial begin
$display("Half Adder test begin!!");    // 加入此行
$dumpvars;
$dumpfile("testha.dmp");

#0 a=0;
   b=0;
   $display($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX); // 加入此行

然後執行模擬,我們可以得到以下螢幕輸出:

Half Adder test begin!!
                   0=>a=0,b=0,sumX=x,coutX=x

從以上輸出我們可以得到當 a=0, b=0 的時候,sumX 跟 coutX 的值為 x (未知)。為什麼會有這個輸出結果 ?



原因:所有的電路都有延遲,當訊號在第 0 秒輸入時,不可能輸出就跟著改變。因此,
我們可以再修改程式碼如下:

#0      a=0;
        b=0;
        $display($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX);

#1
        $display($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX);

其輸出為:
Half Adder test begin!!
                   0=>a=0,b=0,sumX=x,coutX=x
                   1=>a=0,b=0,sumX=0,coutX=0

我們可以觀察上面的第二行,發現在第 1 個時間單位時,sumX=0, coutX=0。這表示經過一個時間單位的延遲之後,電路已完成運算並在輸出端看到結果。

現在有個問題,萬一我們每個訊號的改變都希望能從螢幕上看到數值,該如何作 ?

1. 每一個訊號改變都加上 $display ==> 累死人,我們最好不要作這種蠢事

2. 使用 $monitor ==> 比較聰明的作法

因此我們可以將測試檔改成:

initial begin
$display("Half Adder test begin!!");                            // 加入此行
$monitor($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX); // 加入此行
$dumpvars;
$dumpfile("testha.dmp");

#0      a=0;
        b=0;

其輸出為:

Half Adder test begin!!
                   0=>a=0,b=0,sumX=0,coutX=0
                  10=>a=0,b=1,sumX=1,coutX=0
                  20=>a=1,b=0,sumX=1,coutX=0
                  30=>a=1,b=1,sumX=0,coutX=1


我們可以看到只要加一行 $monitor 之後,系統即會根據輸出/入的變化而自動列印其數值,不必每一行都加 $display。

RTL level 的程式寫法

連接運算子 (p 5-19)

請將 half adder 以 rtl 方式撰寫出來


//RTL Level code                    | // Gate Level code
//ha_rtl.v                                 | // ha_gate.v
module half_adder(x, y, Sum, Cout); | module half_adder(x, y, Sum, Cout);
                                               |
input x, y;                                | input x, y;
output Sum, Cout;                   | output Sum, Cout;
reg Sum, Cout;                       |
                                              | // Circuit Description
// Circuit Description              |
                                             | xor xor0(Sum, x, y);
always @ (x or y)                  | and and0(Cout, x, y);
{Cout,Sum} = x+y;               |
                                            | endmodule
endmodule                           |

上面左邊的程式碼是告訴我們以 RTL 方式撰寫出來的 code,現在我們希望能將寫完的程式進行模擬,請執行:

cver ha_rtl.v test_ha.v

此時我們可以看到

1. $monitor 輸出與之前 ha_gate.v 相同
2. testha.dmp 亦相同


使用 continuous assignment 來撰寫 half adder:

module half_adder(x, y, Sum, Cout);

input x, y;
output Sum, Cout;

// Circuit Description

assign {Cout, Sum} = x + y;

endmodule

上面的例子是使用 assign 語法 (又稱為 continuous assignment,課本 p5-2) 來進行 half adder 的設計。

小結:在這三個半加器的例子中,我們使用了同一個 test fixture 來針對我們所寫的三個不同語法之半加器進行測試,而且測試後之結果均一模一樣。







2011年5月1日 星期日

使用 FPGA 驅動 I/O

傳統的(最常見的) I/O 介面可以分為以下幾種類型:

I:jumper、dip switch、keypad
O:LED、7 seg display、LCD

要驅動這些 I/O,必須知道這些 I/O 背後的工作原理,不同的 I/O 有不同的工作

原理,如果我們連基本工作原理都弄不清楚,那要如何寫程式來驅動這些 I/O ?

如果我們要在 4 顆相連的七段顯示器顯示出 1234,那該如何處理 ?

要顯示 1 -> 1,9         (6)
要顯示 2 -> 5,1,11,12,8 (3)
要顯示 3 -> 5,1,9,11,8  (2)
要顯示 4 -> 4,8,1,9     (7)

其中()內的數字指的是共陽或共陰的腳位。我們依序點亮上面的數字會發現要使用快速掃瞄電路很快將 1->2->3->4 掃瞄過一次,如以下影片所示:

http://www.youtube.com/watch?v=qxGxtjlfhTE

基於人類「視覺殘留」的原理,我們會以為 1234 是同時顯示的。

2011年3月15日 星期二

針對 test fixture 的再進化

我們剛剛寫好的 test fixture 有什麼缺點 ?

缺點1. 我們所測試出來的波形,系統無法自行判斷是正確或是錯誤的波形,得要由人類的眼睛來判斷。

缺點2. 輸入波形無法自動產生


針對缺點1之解決方式

我們使用行為模式(behavior model)來撰寫 testfixture,其目的是讓 testfixture 能自動產生 x+y 的半加器輸出,如下圖所示:



我們的目的是希望在 testfixture 中撰寫一個 behavior 模式之 Half Adder,此 Half Adder 將產生 coutY 及 sumY 之輸出,程式碼如下:

reg sumY, coutY;        // test result

// self calculate coutY, sumY
always @ ( a or b)
  begin
    {coutY, sumY} = a+b;
  end

並以此輸出來與原始 ha_gate/ha_rtl/ha_cont.v 中電路所產生之輸出作比對。

reg testok;             // 0 == error, 1 == testok;

// compare
always @ ( coutX or sumX )
begin
  if ( coutX == coutY && sumX == sumY)
    testok=1;
  else
    testok=0;
end

我們可以觀察 testok 的波形,當 testok == 1 時,我們的電路輸出與自動產生之電路輸出是一致的,如下圖所示。


萬一 testok == 0 時,兩者不一致,運算有錯,必須進行除錯。下圖是一個「故意寫錯」的例子,我們可以發現 {coutY, sumY} = b;,此時 testok 的值會有出現 0 的狀態,這表示它有問題了。


練習:將你之前所完成之 full adder testfixture 加上自我測試程式以自動偵測結果是否正確。


針對缺點2之解決方式
a. 定義一個 clock 訊號源
b. 利用 clock 訊號源來產生訊號

作業2:請使用
       a. gate level 之寫法
       b. always 之寫法
       來撰寫 4 位加/減法器電路,電路圖在 ftp://163.26.229.6/VLSI/addsub.pdf

       請注意:所使用的 test fixture 要為同一個

RTL level 的程式寫法

請將 half adder 以 rtl 方式撰寫出來

// RTL Levl Code

//ha_rtl.v


module half_adder(x, y, Sum, Cout);

input x, y;

output Sum, Cout;

reg Sum, Cout;


// Circuit Description


always @ (x or y)

{Cout,Sum} = x+y;


endmodule
// Gate Level Code

//ha_gate.v

module half_adder(x, y, Sum, Cout);

input x, y;

output Sum, Cout;



// Circuit Description


xor xor0(Sum, x, y);

and and0(Cout, x, y);


endmodule


上面左邊的程式碼是告訴我們以 RTL 方式撰寫出來的 code,現在我們希望能將寫完的程式進行模擬,請執行:

cver ha_rtl.v test_ha.v \Enter

此時我們可以看到

1. $monitor 輸出與之前 ha_gate.v 相同
2. testha.dmp 亦相同


使用 continuous assignment 來撰寫 half adder:

module half_adder(x, y, s, c);
input x, y;
output s, c;
wire x, y;
wire s, c;

assign {c, s} = x + y;

endmodule

上面的例子是使用 assign 語法 (又稱為 continuous assignment) 來進行 half adder 的設計。

小結:在這三個半加器的例子中,我們使用了同一個 test fixture 來針對我們所寫的三個不同語法之半加器進行測試,而且測試後之結果均一模一樣。


$display $monitor 用法

$display 語法 (課本 p2-10 - p2-12)

$display("Hello world")

可以在螢幕上顯示 Hello world 字串,在半加器的測試檔中作以下修改:

initial begin
$display("Half Adder test begin!!");    // 加入此行
$dumpvars;
$dumpfile("testha.dmp");

#0 a=0;
   b=0;
   $display($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX); // 加入此行

然後執行模擬,我們可以得到以下螢幕輸出:

Half Adder test begin!!
                   0=>a=0,b=0,sumX=x,coutX=x

從以上輸出我們可以得到當 a=0, b=0 的時候,sumX 跟 coutX 的值為 x (未知)。為什麼會有這個輸出結果 ?


原因:所有的電路都有延遲,當訊號在第 0 秒輸入時,不可能輸出就跟著改變。因此,我們可以再修改程式碼如下:

#0      a=0;
        b=0;
        $display($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX);

#1
        $display($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX);

其輸出為:
Half Adder test begin!!
                   0=>a=0,b=0,sumX=x,coutX=x
                   1=>a=0,b=0,sumX=0,coutX=0


我們可以觀察上面的第二行,發現在第 1 個時間單位時,sumX=0, coutX=0。這表示經過一個時間單位的延遲之後,電路已完成運算並在輸出端看到結果。

現在有個問題,萬一我們每個訊號的改變都希望能從螢幕上看到數值,該如何作 ?

1. 每一個訊號改變都加上 $display ==> 累死人,我們最好不要作這種蠢事
2. 使用 $monitor ==> 比較聰明的作法

因此我們可以將測試檔改成:

initial begin
$display("Half Adder test begin!!");                            // 加入此行
$monitor($time, "=>a=%b,b=%b,sumX=%b,coutX=%b",a,b,sumX,coutX); // 加入此行
$dumpvars;
$dumpfile("testha.dmp");

#0      a=0;
        b=0;

其輸出為:

Half Adder test begin!!
                   0=>a=0,b=0,sumX=0,coutX=0
                  10=>a=0,b=1,sumX=1,coutX=0
                  20=>a=1,b=0,sumX=1,coutX=0
                  30=>a=1,b=1,sumX=0,coutX=1


我們可以看到只要加一行 $monitor 之後,系統即會根據輸出/入的變化而自動列印其數值,不必每一行都加 $display。

2011年3月13日 星期日

如何使用 GPL Cver 模擬工具

1. 如何撰寫 Verilog 程式

K書、上課、被當,經過上面的循環,你就會寫 Verilog 程式了。

2. 如何模擬 Verilog 程式

有許多不同的 Verilog 模擬程式,例如:
Altera Quartus II
Cadence Verilog XL
Synopsys VCS
Mentor Graphics Modelsim

上面這些模擬軟體最大的「缺點」是其為商業版,非常昂貴,同學只能在學校使用,無法回家進行練習。因此為了讓各位同學能回家練習,我們上半學期使用 GPL Cver 這套免費的 Verilog 模擬程式。下圖是我們進行 FPGA 時會使用到的流程及工具:






3. 什麼是 Cver

Cver 是由 Pragmatic C Software (http://www.pragmatic-c.com/) 這家公司所發展出來的,在 Cver 發展的時候, Pragmatic 遭遇了 Cadence 及 Synopsys 的夾擊,因此 Cver 在市場推廣不好,因此後來 Pragmatic 決定將 Cver 以 GPL 授權釋出。僅管 Cver 現在是免費的,但不表示他不好用,他的特色是:

1. full 1995 IEEE P1364 - 完整支援 1995 IEEE P1364 標準
2. some of the 2001 P1364 - 部份 2001 P1364 標準
3. 支援三個 PLI 介面 (tf_, acc_, and vpi_)

所以其功能相當適當一般入門至進階同學使用。

4. 如何安裝 GPL Cver

目前 GPL Cver 的官方網址已移至 source forge (http://gplcver.sourceforge.net/),如果你的系統是安裝 Debian 6.0,請執行

apt-get install gplcver

如果不是,請自己想辦法。

5. 如何測試你的系統已安裝 GPL Cver

請執行:
cver \Enter

如果你的系統已安裝 GPL Cver 的話,會出現以下訊息:

GPLCVER_2.12a of 05/16/07 (Linux-elf).
Copyright (c) 1991-2007 Pragmatic C Software Corp.
  All Rights reserved.  Licensed under the GNU General Public License (GPL).
  See the 'COPYING' file for details.  NO WARRANTY provided.
Today is Mon Mar  7 09:51:55 2011.
**FATAL ERROR** [301] no Verilog input files specified

最底下的

**FATAL ERROR** [301] no Verilog input files specified

是警告我們沒有提供 verilog 檔給 cver 模擬,但是這不表示 Cver 有問題。

5. 如何使用 Cver
請執行:

cver a.v test_a.v \Enter


6. Module 的命名方式:

要為一個 Verilog 的 Module 命名,最大的前題是:N 年後你知道這是什麼電路,如何使用此電路。舉例來說:以下二個 module 那一個比較好 ?

module half_adder()
endmodule

module ha()
endmodule

假設此電路程式放了 N 年,N 年後你還會認得的是 half_adder 還是 ha ? 所以在替 module 命名時,不要偷懶,免得無法重複使用。

7. Verilog 的存檔命名:

假設你使用 gate level 的方式撰寫 half adder,請問以下二個存檔那一個比較好 ?

ha.v
ha_gate.v
ha_rtl.v -> 以 RTL 方式所寫的 half adder

答案很明顯是 ha_gate.v,它在檔名就告訴我們這是 gate level 的存檔。

8. 如何撰寫 test fixture (測試程式)

8.1 什麼是 test fixture ?

當我們寫完 verilog 電路後,我們必須證明它是對的,因此我們要寫 test fixture 來針對我們所寫的 verilog 程式進行測試。

8.2 test fixture 的內容

一個 test fixture 就是一個 verilog module,以半加器 test fixture 為例,其語法大致如下:

module test_ha;
reg   definition  -> 暫存器定義
wire  definition  -> 線定義
other definition  -> 其它定義

half_adder ha0 () -> 呼叫我們要進行測試的電路

initial begin                   -> 開始進行波形輸入
$dumpvars;                      -> 產生 gtkwave 語法
$dumpfile("testha.dmp");        -> 將波形以 VCD 格式存在 testha.dmp 檔中,
                                   testha.dmp 可照自己的需求改名字

simulation command   模擬指令,以下特別說明!!

$dumpall;                       -> 紀錄所有訊號
$dumpflush;                     -> 必要
#10 $finish;                    -> 在 10 個時間單位後結束模擬
end                             -> 結束 initial begin
end                             -> 結束 initial begin
endmodule

在 simulation command 的部份,我們需要針對半加器的動作來進行完整測試,請問什麼是半加器的完整測試 ? 要判別一個半加器是否完整動作,最簡單的方法是把真值表上的每一列都模擬一次,如果輸出/入之狀態完全符合真值表,則我們可以確認此電路工作正常。

x  y | Sum   Cout
-----+-----------
0  0 |   0      0
0  1 |   1      0
1  0 |   1      0
1  1 |   0      1


因此一個完整的半加器 test fixture 如下,我們將其存為 test_ha.v

1 module test_ha;
2 reg a, b;
3 wire sumX, coutX;
4
5 half_adder ha0(a, b, sumX, coutX);
6
7 initial begin
8 $dumpvars;
9 $dumpfile("testha.dmp");
10
11 #0 a=0;
12 b=0;
13
14 #10 a=0;
15 b=1;
16
17 #10 a=1;
18 b=0;
19
20 #10 a=1;
21 b=1;
22
23 $dumpall;
24 $dumpflush;
25 #10 $finish;
26 end
27 endmodule

8.3 進行 verilog 測試模擬

請執行

cver ha_gate.v test_ha.v \Enter

理論上應該輸出如下:

GPLCVER_2.12a of 05/16/07 (Linux-elf).
Copyright (c) 1991-2007 Pragmatic C Software Corp.
  All Rights reserved.  Licensed under the GNU General Public License (GPL).
  See the 'COPYING' file for details.  NO WARRANTY provided.
Today is Mon Mar  7 11:25:30 2011.
Compiling source file "ha_gate.v"
Compiling source file "test_ha.v"
Highest level modules:
test_ha

Halted at location **test_ha.v(25) time 40 from call to $finish.
  There were 0 error(s), 0 warning(s), and 4 inform(s).

我們會發現沒有 error、沒有 warning,而且會有個檔案叫 testha.dmp,接下來就可以用 GTKwave 觀察波形了。


9. 使用 GTKwave

請執行

gtkwave testha.dmp

來載入模擬波形檔


作業 1. 畫 Full Adder 的電路圖
        以 Gate Level 寫 Verilog 程式
        撰寫 test fixture,並跑模擬,可存檔檔名為 testfa.dmp
        列印波形

2011年2月21日 星期一

FPGA 上課講義 2012/02/13

光碟片的演進:
  1. CDROM -> 唯讀光碟:由工廠生產(壓片),使用者只能讀、不能寫
  2. CDR -> 可寫一次光碟、使用者可寫一次,無法抹除
  3. CDRW -> 可讀可寫光碟,使用者可以抹除
IC 的演進:
  1. ROM -> 唯讀記憶體,由工廠生產(燒錄),使用者只能讀、不能寫
  2. PROM -> 可寫一次記憶體,使用者可寫一次,無法抹除
  3. EPROM、EEPROM、Flash -> 可讀可寫記憶體,使用者可以抹除
-------上述記憶體所儲存的為 ? 資料 ------
  1. PLA、PAL -> 可寫一次電路(可程式化電路),主要以數位電路為訴求 (http://zh.wikipedia.org/zh-tw/可程式邏輯裝置)
  2. FPGA -> 可讀可寫之電路 (可程式化電路),主要以數位電路為訴求 (http://zh.wikipedia.org/zh-tw/FPGA)
例如,使用 PLA/PAL 來實現以下電路。
F=A+B'‧C

未來上課內容所打的講義都會放在:http://pominglee.blogspot.com/

本課程期中、期末目標如下:
  1. 期中考前:進行 Verilog 程式教學,使用工具為 GPL cver,使用之波形觀測軟體為 GtkWave
  2. 期中考後:進行實際電路下載 FPGA 電路板教學,使用工具為 Altera Quartus II,本學期主要實習電路為 Altera 系統。
寫 Verilog 的流程如下:
  1. 撰寫 Verilog 程式 (使用工具:vi)
  2. 模擬 Verilog (使用工具:cver)
  3. 觀察 Verilog 執行結果 (使用工具:gtkwave)
  4. 除錯 -> 修改原始程式 -> 一直到電路設計完成


半加器程式:

module halfadder(x, y, s, c);
input x, y;
output s, c;
wire x, y;
wire s, c;

assign {c, s} = x + y;


endmodule


A0 A1 A2 A3 B0 B1 B2 B3 S0 S1 S2 S3 Cout
0   0  0  0  0  0  0  0
0   0  0  0  0  0  0  1
..
             1  1  1  1
0   0  0  1  0  0  0  0
0   0  0  1  0  0  0  1
..
             1  1  1  1


Prac.

試設計一 4 位元加/減法器,並執行完整模擬且確定其功能正確。

a. 以 Gate Level 方式撰寫此電路
b. 以 RTL  Level 方式撰寫此電路
c. 回家搞懂什麼叫 Gate Level/RTL Level
行話