#2 數位電路設計


教學資源

先修課程 數字系統
數位電路設計 Digital System Design 開放式課程
課程教材 Chapter 01
課程教材 Chapter 02
課程教材 Chapter 03
課程教材 Chapter 04
課程教材 Chapter 05
課程教材 Chapter 06
課程教材 Chapter 07
卡諾圖線上簡化工具

筆記

Enable

如何控制一個 and gate 或 or gate。

Deocder

這是一張普通的 3x8 line decoder,設計上沒有任何問題,但不夠佳。可以看出 fan-in 也就是 input 的數量 ≥ 2,當一個 gate 的 fan-in 過高會有一些問題,因為一個 input 就是一個訊號輸入,當訊號數多時雜訊也就多,訊號會變得不乾淨;次要會因電流問題導致延遲提高,讓電路變得非常慢,這點在 fan-out (ouput) 同理;最後 gate input cost 則十分不合成本,接下來有一種優化的方式可以對照,但這點在 3x8 還看不太出來。

這種方式稱為 hierarchy (階層) 設計,下面就是將 3x8 decoder 拆成 1x2 + 2x4 整合起來 (紅色部分),當然,其中 2x4 decoder 還可以再拆成 2 個 1x2 decoder 整合起來 (綠色部分),處理 fan-in 問題。

在 3x8 decoder 中 GIC 兩個方式皆為 27,但到了 6x64 decoder 中,GIC 明顯少很多。

在 decoder 當中,可以加入 enable,透過 enable (w),控制 D0 to D7 或 D8 to D15 部分,這也是一個 hierarchy 設計,把 4x16 拆成 2 個 3x8 decoder。

Encoder

另外一種應用,指抓最前面。

Multiplexers

就是 decoder + enable + or gate,多工器上有 selecter 可以 select 哪一條線的資料被送出。

Others

像是 rom、pla、pal、lookup tables (read write memory) 這些全都歸類為 memory 類。

implement combinational logic function

看完了上面學到的組合電路,現在把他當作一個 function block 實作各種 boolean function。
(1) using decoder
取 S 還是 S' 是門專業,記得 nand gate 比較便宜。

之後還有很多 using mux, rom, pla, pal, lookup talbe 等。
第五章就是做加減法器 half adder, full adder 之類。
接下來很快就到了 sync(同步) sequential circuit,async 太難了這邊都只教 sync,以前我不知道 latches 跟 flip-flops 到底差在哪裡,終於在今天豁然開朗 flip-flops 其實就是 latches + enable 而已,有 positive-edge-trigger, negative-edge-trigger 兩種 transition。
第六章跟第七章印象中我很快地就混了過去 XDD。

實作部分

教學資源

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 類似

組合邏輯電路

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







你可能感興趣的文章

旅程開始

旅程開始

[Note]  JS: Scroll events

[Note] JS: Scroll events

筆記、程式設計概論

筆記、程式設計概論






留言討論