#4 FPGA 設計


教學資源

Moocs FPGA系統設計實務

筆記

前言

得先念完數位系統設計,這就是把理論的數位電路直接實作出來,教學軟體是 Quartus® II,有種既熟悉又陌生的味道。一開始先介紹 FPGA 產業、設計流程,蠻好理解的,除了有一堆物理半導體材料的東西除外 XD。第一次接觸拉了一個 full adder出來:然後用 full adder 再組成一個 4 bit 的 ripple carry adder。建立波形模擬圖驗證結果。以上的練習都是直接拉 pin 與 logic gate 沒有寫 verlog。
有個好用的工具,tools -> netlist viewers -> RTL viewer 可以把剛寫的 HDL code 轉換成邏輯閘圖。一樣用波形驗證,看到 F 跟 truth table 一樣就對了。要回去重新設計 ripple_carry_adder 了,這次不用圖,而是以 verlog 實現,為此我們需要先有一支 full_adder 的 module,這樣就能夠造出 4 個 full_adder 來完成任務。

module full_adder(a, b, c_in, sum, c_out);

input a, b, c_in;
output sum, c_out;

wire w1, w2, w3;

xor x1(w1, a, b),
    x2(sum, w1, c_in);

and a1(w2, a, b),
    a2(w3, w1, c_in);

or o1(c_out, w2, w3);

endmodule
``` fa0 表第一個 full_adder,裡面放參數,這是 by name 方式,舉例來說 .sum 表示 sum 參數送 sum[0] 進去這樣,以此類推。
``` c
module ripple_carry_adder_verlog(a, b, c_in, sum, c_out);

input [3:0] a, b;
input c_in;
output [3:0] sum;
output c_out;

wire w0, w1, w2;

full_adder fa0(.c_out(w0),
               .a(a[0]),
               .b(b[0]),
               .c_in(c_in),
               .sum(sum[0])
);

full_adder fa1(.c_out(w1),
               .a(a[1]),
               .b(b[1]),
               .c_in(w0),
               .sum(sum[1])
);
full_adder fa2(.c_out(w2),
               .a(a[2]),
               .b(b[2]),
               .c_in(w1),
               .sum(sum[2])
);
full_adder fa3(.c_out(w3),
               .a(a[3]),
               .b(b[3]),
               .c_in(w2),
               .sum(sum[3])
);

endmodule

直接看程式不直覺,這裡有一張概念圖配合著看,就很容易理解了。RTL viewer 出來的結果:

verlog

上面都是跟著課程邊看邊寫的,對 verlog 還不是很熟,我看是時候要認真打一下 verlog 的基礎了,免不了要從宣告開始:

數值的部分 <size>'<base><number>
18'h47CB  宣告 18 bit 的 16 進制 47CB 值,若有高位補 0
13'h47CB  13 bit 不夠表示 47CB (要 15 bit),少的地方會直接被砍掉,要注意 
5'b1xx11 宣告 5 bit 的二進制 1xx11 值,x 可以為 0 or 1 表示不確定
'o723 沒有宣告就以 complier 內定長度來表示,宣告 32 bit 的 8 進制 723 值
資料物件與型態
1. wire 實體元件的連接線 (Nets),內定值為 z (高阻抗斷路),一位元為 scalar,多位元為 vector
wire w = 1'b0; 宣告一條名為 w 的接線,並指定它為 false
2. registers 暫存器,內定值 x
reg r; 宣告一個 1 bit 名為 r 的暫存器,內定值為 1 bit 的 x
屬於暫存器關鍵字除了 reg 之外還有:interger, real, time
interger a; 32 bit 寬的有號整數,宣告一個整數 a,值可以正負
real b; 雙倍精度的有號浮點數,宣告一個浮點數 b,值含小數點
time c; 64 bit 寬的無號整數
scalar 和 vector
scalar:沒有特別宣告,內定 1 bit
vector:[7:0] or [0:7],但不管是哪一種,在最左(右)邊的一律是數值中的最高(低)位元 [MSB:LSB]
wire [3:0] x; 宣告一條 4 bit 名為 x 的接線
reg [0:31] y; 宣告一個 32 bit 名為 y 的暫存器
陣列 array
多個 wire 或 registers 的聚合體,定義類似記憶體或暫存器檔案
reg [31:0] 1D_block [127:0]; 宣告 1D_block 是一個包含 128 個 reg 的 1-D array,每個 reg 都是 32 bit
reg [7:0] 2D_block [3:0][63:0];  宣告 2D_block 是一個  4x64 的 2-D reg array,每個 reg 都是 8 bit
參數 parameters
定義編譯合成電路的常數,個人覺得類似於 c 語言裡面的變數 (?)
parameters width = 4;
wire [width-1:0] w; 宣告 4 bit 的 w 線,如果要改成 5 bit,就把上面 width 改成 5
reg [0:width-1]; reg 同樣適用

模組 module
module 內部電路描述可包含:引用其他 module、wire or reg 訊號資料型態宣告、assign 資料處理模型描述、always 行為模型描述、function 函數、task 任務等

埠 port
就是 input、output、inout 這三種,宣告型態內定為 wire,要儲存就要宣告成 reg
ps. input 跟 inout 卻不能宣告成 reg,因為 input 是接收外來訊號,只能被驅動,而無法儲存

moudle full_adder(a,b,c_in,sum); // 有一個叫 full_adder 的 moudle,裡面有 4 個訊號
input [3:0] a, b; // 定義這些訊號分別為何
input c_in;
output sum;
reg sum; // 輸出 sum 須被儲存,所以宣告成 reg
...
endmodule

module 內有很多的模型

邏輯閘層次模型
簡單來說就是平常看到的各種 logic gate,輸出一定要用 wire 連接,在 port 的第一個一定要是 output
1. gate_type instance(out, in_1, in_2, ... in_n);
and a1(f, w, x, y, z); // 簡單地做好了一個 fan-in 為 4 名為 a1 的 and gate,輸出為 f
2. gate_type instance(out_1, out_2, ... out_n, in);
not n1(a, b, c, f); // 簡單地做好了一個 fan-out 為 3 名為 n1 的 not gate,輸入為 f
3. 超簡單範例:and_or_gate
module and_or_gate(in1, in2, in3, in4, f);
input in1, in2, in3, in4;
wire w1, w2;
output f;
and a1(w1, in1, in2);
and a2(w2, in3, in4);
or o1(f, w1, w2);
endmodule
結構式模型
是引用子模組的設計方法,port 有 in order 跟 by name 兩種對應方法,下圖表模組間訊號的型態
![](https://static.coderbridge.com/img/myg36t91/a45ff04de7fe420398edad6198e93085.jpg)
上面設計的 ripple_carry_adder 引用了 full_adder 子模組,而在 full_adder 裡面又用了邏輯閘層次模型
資料處理模型
關鍵字 assign,後面通常接運算式,等號左邊一定是 wire,右邊沒規定
wire w1, a, b;
assign w1 = a & b; // a & b 是一個運算式的表現,表達 and 運算
正種寫法被稱為正規式持續指定,也有隱藏式的寫法
wire w2 = a & b // assign 直接被消失
拿超簡單範例:and_or_gate 用資料處理模型來呈現
module and_or_gate(in1, in2, in3, in4, out);
input in1, in2, in3, in4;
output out;
out = (in1 & in2)|(in3 & in4);
endmodule

邏輯、算術運算子這種東西都聽到膩了,只是這邊有新的概念:連結 {}、重複 {{}}、簡化運算子

wire A = 1'b1
wire [1:0] B = 2'b10;
wire [2:0] C = 3'b111;
連結 assign Y1 = {B, C}; // Y1 = 5'b10_111 (底線只是為了區隔,complier 不會有任何影響)
連結 assign Y2 = {C, A, B[0]} // Y2 = 'b111_1_0
重複 assign Y3 = {{3{C[2:1]}}, {2{B}}, A}; // 取 C[2:1] 重複三次 + 取 B 重複兩次 + A。Y3 = 'b11_11_11_10_10_1
input X = 4'b1001;
簡化 assign O1 = &X; // O1 = 1 and 0 and 0 and 1 = 0
簡化 assign O2 = |X; // O2 = 1 or 0 or 0 or 1 = 1
簡化 assign O3 = ^X; // O3 = 1 xor 0 xor 0 xor 1 = 0
行為描述模型
最高階的層次模型,包含 if else 之類的條件敘述,關鍵字是 initial 跟 always
輸出資料 (等號左邊) 要用 reg 宣告,用 begin ... end 包覆,= 會按順序執行,而 <= 不會
1. initial 只執行一次的東西,區塊內的 
reg a, b, c;
initial
begin
    a = 'b111;
    b = 'b101;
    c = a & b;
end
2. always 反覆執行的東西,@(事件觸發表示式:準位 or 邊緣觸發)
alwyas @(signal or posedge/negedge clk)
begin
    c = a & b;
end
3. case-endcase 範例,x = don't care
casex(singal)
2'b0x: out = a;
2'b10: out = b;
default: out = 2'b00;
endcase
4. forever、repet (次數) 範例
reg clock;
initial
begin
clock = 1'b0;
forever clock #5 = ~clock; // 延遲 5 個單位時間後做反向,藉此做出週期性訊號
repet (3) clock #5 = ~clock;
end
函數 function,類似副程式的概念,不能有 delay、而且至少要有一個輸入
function [?:?] <function_name>; // funtion_name 相當於 function 的回傳值,complier 會定義出相同名稱的 reg 資料型態,所以可以在前面加 [?:?]
module min(a, b, c, x, y);
input [3:0] a, b, c;
output [3:0] x, y;
reg [3:0] x, y;
always @(a, b, c)
begin
    x = min_fun(a, b);
    y = min_fun(a, c);
end
function [3:0] min_fun;
intput [3:0] in1, in2;
begin
...
end
endfunction
endmodule

而 task 跟 function 類似

組合邏輯電路

多工器比較器編碼器解碼器七段顯示器

循序邏輯電路







你可能感興趣的文章

[Day07] Monad

[Day07] Monad

PHP、MySQL 語法基礎

PHP、MySQL 語法基礎

打包你的Python程式~PyInstaller基礎篇

打包你的Python程式~PyInstaller基礎篇






Comments