2014年11月30日 星期日

Sedra/Smith Chapter 4 Bipolar Junction Transistors (BJTs)


Sedra/Smith  Microelectronic Circuits 6/E 

Chapter 4-A

Bipolar Junction Transistors  (BJTs) 


http://www.mediafire.com/view/vbv1o9fb1psw9ai/2014-12-01-CH04-A.pdf

2014年11月22日 星期六

P11-10 傳統乘法器的改進 P = A * B



乘法中“負值正值的關係”就是“互斥或的關係”。

          A                         B                      結果
          (0)                     (0)                      (0)
          (0)                     (1)                      (1)
          (1)                      (0)                      (1)
          (1)                     (1)                      (0)

 AxB=C
 3x4=12;
-3x4=-12;
3x-4=-12;
-3x-4 =12;

從上面的內容看來,無論A值和B值是什麼樣的“正值和負值的關係,結果C都是一
樣。

傳統的乘法器
該乘法器的大致操作如下:
      (一)在初始化之際,取乘數和被乘數的正負關係,然後取被乘數和乘數的正值。
      (二)每一次累加操作,遞減一次乘數。直到乘數的值為零,表示操作結束。
      (三)輸出結果根據正負關係取得。

傳統乘法器的改進

VerilogHDL 語言所描述的乘法器是以“消耗時鐘”作為時間單位。反之組合邏輯所建
立的乘法器是以“廣播時間”作為時間單位。說簡單點就是,VerilogHDL 語言所描述
的乘法器“快不快”是根據“時鐘消耗”作為評估。

假設 A=10,B=20, AxB ,那麼時鐘的消耗至少需要20個,因為 A值需要累加20
次才能得到結果。到底有沒有什麼辦法可以改進這個缺點呢?有學過乘法的朋友都知道
A ( B) 等價於 B (A )。如果以實驗一的乘法器作為基礎,那麼 A(B ) B(A ) 所消
耗的時間就不一樣了。結果我們可以這樣改進:

如果被乘數小於乘數,那麼被乘數和乘數互換。

{Multiplier,Multiplicand}=Multiplicand<Multiplier?{Multiplicand Multiplier}:
                          {Multiplier Multiplicand}

舉個例子:Multiplicand =2 Multiplicand =10;

在更換之前, 被乘數2 需要10次的累加才能得到結果,亦即需要消耗至少10個時鐘
才能求得結果。 更換之後, 被乘數為10 乘數為2,亦即被乘數10只要累加2次就能
得到結果,所以時鐘的消耗是2個以上。如此一來,10次的累加次數和2次的累加次數
相比,可以減少不少時鐘的消耗。




blocking與nonblocking

源自於
http://www.cnblogs.com/oomusou/archive/2010/07/30/blocking_vs_nonblocking.html

深入探討blocking與nonblocking (SOC) (Verilog)

Abstract
Verilog雖然是個語法簡單的語言,但是blocking與nonblocking卻是大家學習Verilog時永遠的痛,即時是很資深的IC Designer,也未必完全搞清楚兩者的差異,本文試著以simulator與synthesizer的角度去探討之。
Introduction
使用環境:NC-Verilog 5.4 + Debussy 5.4 v9 + Quartus II 7.2
軟體的語言都是一行一行依序執行,這與Verilog的blocking觀念一樣,但偏偏Verilog還有個nonblocking,而且在寫同步電路時,還一定得用nonblocking寫,到底blocking與nonblocking有什麼不同呢?我在(筆記)如何使用blocking與nonblocking assignment? (SOC) (Verilog)這篇討論過幾個簡單的原則,基本上只要依照這幾個原則去寫RTL,就能保證simulation的與synthesis的結果一致,但當時我並沒有討論其原因,只是將規則背下來而已。
在正式討論之前,請各位先做個小測驗,考驗您的觀念是否正確:
blocking.v / Verilog 
复制代码
1 /* 2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3 
4 Filename    : blocking.v5 Simulator   : NC-Verilog 5.46 Description : blocking assignment in always block7 Release     : Jul/30/2010 1.08 */
9 
10 module blocking (11   clk,12   rst_n,13   a_i,14   b_i,15   a_o,16   b_o17 );18 
19 input clk;20 input rst_n;21 input a_i;22 input b_i;23 output a_o;24 output b_o;25 
26 reg a;27 reg b;28 
29 assign a_o = a;30 assign b_o = b;31 
32 always@(posedge clk or negedge rst_n) begin
33   if (~rst_n) begin
34     a = a_i;35     b = b_i;36   end
37   else begin
38     a = b;39     b = a;40   end
41 end
42 
43 endmodule
复制代码
blocking_tb.v / Verilog 
复制代码
1 /* 2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3 
4 Filename    : blocking_tb.v5 Simulator   : NC-Verilog 5.46 Description : testbench of blocking assignment in always block7 Release     : Jul/30/2010 1.08 */
9 
10 `include "blocking.v"
11 
12 module blocking_tb;13 
14 reg clk;15 reg rst_n;16 reg a_i;17 reg b_i;18 wire a_o;19 wire b_o;20 
21 initial begin
22   clk = 1'b0;
23   rst_n = 1'b0;
24   a_i = 1'b1;
25   b_i = 1'b0;
26   #5;27   rst_n = 1'b1;
28   #100;29   $finish;30 end
31 
32 always #10 clk = ~clk;33 
34 initial begin
35   $fsdbDumpfile("blocking.fsdb");36   $fsdbDumpvars(0, blocking_tb);37 end
38 
39 blocking blocking_0 (40   .clk(clk),41   .rst_n(rst_n),42   .a_i(a_i),43   .b_i(b_i),44   .a_o(a_o),45   .b_o(b_o)46 );47 
48 endmodule
复制代码
nonblocking.v / Verilog 
复制代码
1 /* 2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3 
4 Filename    : nonblocking.v5 Simulator   : NC-Verilog 5.46 Description : nonblocking assignment in always block7 Release     : Jul/30/2010 1.08 */
9 
10 module nonblocking (11   clk,12   rst_n,13   a_i,14   b_i,15   a_o,16   b_o17 );18 
19 input clk;20 input rst_n;21 input a_i;22 input b_i;23 output a_o;24 output b_o;25 
26 reg a;27 reg b;28 
29 assign a_o = a;30 assign b_o = b;31 
32 always@(posedge clk or negedge rst_n) begin
33   if (~rst_n) begin
34     a <= a_i;35     b <= b_i;36   end
37   else begin
38     a <= b;39     b <= a;40   end
41 end
42 
43 endmodule
复制代码
nonblocking_tb.v / Verilog 
复制代码
1 /* 2 (C) OOMusou 2010 http://oomusou.cnblogs.com
3 
4 Filename    : nonblocking_tb.v5 Simulator   : NC-Verilog 5.46 Description : testbench of nonblocking assignment in always block7 Release     : Jul/30/2010 1.08 */
9 
10 `include "nonblocking.v"
11 
12 module nonblocking_tb;13 
14 reg clk;15 reg rst_n;16 reg a_i;17 reg b_i;18 wire a_o;19 wire b_o;20 
21 initial begin
22   clk = 1'b0;
23   rst_n = 1'b0;
24   a_i = 1'b1;
25   b_i = 1'b0;
26   #5;27   rst_n = 1'b1;
28   #100;29   $finish;30 end
31 
32 always #10 clk = ~clk;33 
34 initial begin
35   $fsdbDumpfile("nonblocking.fsdb");36   $fsdbDumpvars(0, nonblocking_tb);37 end
38 
39 nonblocking nonblocking_0 (40   .clk(clk),41   .rst_n(rst_n),42   .a_i(a_i),43   .b_i(b_i),44   .a_o(a_o),45   .b_o(b_o)46 );47 
48 endmodule
复制代码
以上為完整的RTL與testbench,其實真正的差異只有以下兩部份,其他部分完全一樣:
1.在always block使用blocking
复制代码
always@(posedge clk or negedge rst_n) begin
  
if (~rst_n) begin
    a 
= a_i;
    b 
= b_i;
  
end
  
else begin
    a 
= b;
    b 
= a;
  
end
end
复制代码
2.在always block使用nonblocking 
复制代码
always@(posedge clk or negedge rst_n) begin
  
if (~rst_n) begin
    a 
<= a_i;
    b 
<= b_i;
  
end
  
else begin
    a 
<= b;
    b 
<= a;
  
end
end
复制代码
請先把你自己當成simulator,實際模擬一下結果為何。
以下為使用NC-Verilog + Debussy所模擬的結果:
blocking.v
 nonblocking00
nonblocking.v
nonblocking01
你所預期的結果與simulator一樣嗎?
以Simulator角度探討blocking與nonblocking
blocking
复制代码
always@(posedge clk or negedge rst_n) begin
  
if (~rst_n) begin
    a 
= a_i;
    b 
= b_i;
  
end
  
else begin
    a 
= b;
    b 
= a;
  
end
end
复制代码
先討論較好理解的blocking,所謂的blocking,就是一行程式執行完才能執行下一行,所以在clk rising edge時,先將b的值給a,然後再將a的值給a,也就是說,在clk rising edge之後,a = b = 0,這與C的觀念一樣。
nonblocking
复制代码
always@(posedge clk or negedge rst_n) begin
  
if (~rst_n) begin
    a 
<= a_i;
    b 
<= b_i;
  
end
  
else begin
    a 
<= b;
    b 
<= a;
  
end
end
复制代码
再來討論nonblocking,在clk rising edge時,a <= b,b <= a,這到底要怎麼理解呢?這必須牽涉到simulator的event queue如何處理這些event。
在討論evnet之前,先解釋兩個專有名詞,RHS與LHS。
RHS:在 =  或 <= 右邊的運算式或變數
LHS:在 = 或 <= 左邊的運算式或變數
由於電腦軟體本身是依序執行(也就是如C一樣程式一行一行的執行),但硬體電路卻可併行執行,simulator是軟體寫的,卻要能夠模擬出硬體電路的的並行執行,也就是如在5 ns時,同時有很多信號被處理,所以才有event queue的概念,將同一個time step要處理的信號放在一個event queue,simulator再依序處理,處理完後再處理下一個time step,這樣就能使依序執行的simulator可以模擬出並行執行的硬體電路。
在IEEE Verilog standard定義了以下的event queue讓simulator廠商實作,至於該如何實作是各廠商的商業機密。
  nonblocking06
絕大部分的event都會放在Active Events queue內,包括blocking assignments、blocking的RHS、continuous assignments、$display()..等,也就是說當某個time step到達時,會執行Active Events queue的event,但Verilog IEEE standard並沒有保證在Active Events queue內event的執行順序(所以一些不良的coding style可能會造成race condition,這又是另外一個Verilog很惱人的issue,再另闢專文討論),值得注意的是nonblocking的RHS是放在Active Events queue,但沒有包含nonblocking的LHS。
在IEEE standard有定義演算法介紹其他Event queue如何加進Active Events,在這就不多談,這裡的重點是有一個Nonblocking Events queue專門放nonblocking的LHS,會在適當的時機加入Active Events queue執行。
所以由此可知,由於RHS of nonblocking放在Active Events,所以會先執行,之後等在Nonblocking Events queue的LHS of nonblocking進入Active Events queue後再執行。
因此整個nonblocking可視為兩個步驟的行為:
1.在clk rising edge的一開始執行RHS。
2.在clk rising edge快結束時執行LHS。
所以在 a <= b, b <= a時,clk rising edge一開始先執行RHS,也就是a = 1,b = 0,然後再執行LHS,因此a = 0,b = 1,因此nonblocking不會如blocking因為a已經更新了,因而改變了b的值。可以發現,blocking會因為程式的撰寫順序而有不同的值,但nonblocking卻不會因為程式的撰寫順序而有影響,原因是nonblocking的執行是2個步驟,而blocking的執行是1個步驟
以Synthesizer角度探討blocking與nonblocking
寫Verilog最擔心的是simulation時正常,但synthesis後卻不是你要的,因此我們實際在Quartus II跑看看,看看經過P&R之後,是否與NC-Verilog的結果一樣,並使用RTL Viewer看看Quartus II如何synthesis。
blocking.v
 nonblocking02
nonblocking.v
 nonblocking03
除了加上delay外,基本上波形與NC-Verilog所模擬的一樣。
blocking.v
 nonblocking04
雖然在code中宣告了2個reg,但synthesizer只會合成出1個register,也就是a = b, b = a只delay了1個clk。
nonblocking.v
 nonblocking05
會合成出2個register,符合我們的預期,也就是 a <= b, b <= a會delay 2個clk。

完整程式碼下載
blocking.7z (NC-Verilog + Debussy)
blocking_quartus_ii.7z (Quartus II)
nonblocking.7z (NC-Verilog + Debussy)
nonblocking_quartus_ii.7z (Quartus II)
Conclusion
本文試著用最淺顯易懂的方式解釋blocking與nonblocking的差異,並從simulator與synthesizer的角度同時去思考,若想得知更完整的資訊,可參考Reference的paper與書籍。

任務與函數不同之處


源自於網路及http://www.cnblogs.com/zxl2431/archive/2010/09/28/1837861.html

任務與函數不同之處(Differences between Tasks and
      Functions) 

函數
任務
一個函數可以引用其他的函數,但不能引用其他的任務
一個任務可以引用其他的任務與函數
函數永遠在時間等於零的時候開始執行
任務可以不從時間等於零的時候開始執行
函數不能包含有延遲、事件或是控制時間的任何陳述
任務可以包含有延遲、事件與控制的陳述
函數至少要有一個input的宣告,並能多於一個
任務可以擁有零個或是更多的
input、output或是inout
函數永遠回傳單一個值,並且不能有output與inout宣告
任務並沒有傳回的值,但可藉由output、input將值輸出來



輸入輸出的關鍵字input跟output,對一個任務而言是將訊號傳出彙傳入一個任務的工作而已,並不是一個埠。


當函數宣告的時候,verilog同時也內宣告了一個以函數的名稱為名的暫存器,當函數執行完畢,函數的輸出則經由這個暫存器傳回到我們呼叫函數的地方。



通常函數並不會有遞迴使用的狀況,如果同時間兩段程式呼叫使用同一個函數,因為函數內佔用同一份記憶體空間,會造成無法確認的結果,所以我們利用關鍵字automatic來定義一個自動(允許遞迴)函數,將會動態分配到獨立的空間給函數,彼此不會干擾。範例7-10是利automatic的功能來實作階乘。

Verilog語言中的任何過程模組都從屬於以下4中結構的說明語句:
  (1):  initial說明語句;
  (2):  always說明語句;
  (3):  task說明語句;
  (4):  function說明語句;
  每個initialalways說明語句在仿真的一開始同時立即開始執行。 
  
复制代码
 1  initial
 2
 3
    begin
 4
 5
      areg = 0;                //初始化寄存器
 6
 7
      for(index = 0;index < size;index = index + 1'b1)
 8
 9
        momory[index] = 0;         //初始化一個memory
10
11
    end
12  
复制代码
  在這個例子中用initial語句在仿真時對各變數進行初始化,注意這個初始化的過程不需要任何仿真時間,即在0ns時間內,便可以完成記憶體的初始化工作。
1 always
2     wait(count_enable)  #20 count = count + 1'b1;
  對於always語句除了我們熟知的等待信號值的變化或者時間觸發,使用@和後面的敏感信號列表來表示。Verilog同時也允許使用另一種形式表示的電平敏感時序控制(即後面的語句和語句塊需要等待的某個條件為真才能執行)Verilog語言用關鍵字wait來表示等待電平敏感的條件為真,上面的例子只有當count_enable信號為1有效時,才會執行後面的語句。
  任務、函數的定義和調用都包括在一個module的內部,他們一般用於行為級建模,在編寫Testbench時用的較多,而在寫可綜合的代碼時要少用。
  function的定義:
    function<返回值類型和位元寬> <函數名>
      <入口參量和類型聲明>
      <局部變數聲明>
      行為語句;
  endfunction
  定義function時,要注意以下幾點:
  (1):  function定義結構不能出現在任意一個過程塊(always塊或者initial)的內部;
  (2):  function定義不能包括有任何時間控制語句,即任何用#@wait來標識的語句;
  (3):  定義function時至少要有一個輸入參量;
  (4):  定義function時,在function內部隱式地將函數名聲明成一個寄存器變數,在函數體中必須有一條賦值語句對該寄存器變數賦以函數的結果值,以便調用function時能夠得到返回的函數值。如果沒有指定的返回值的寬度,function將缺省返回1位二進位數字。
  function的調用:
  <函數名>  (<輸入運算式1>,...,<輸入運算式n>) ;
  輸入運算式與函數定義結構中的各個輸入埠一一對應,這些輸入運算式的排列順序必須與各個輸入埠在函數定義結構中的排列順序一致。
  function的調用既可以出現在過程塊中又可以出現在assign連續賦值語句之中;另外,function定義中聲明的所有局部變數寄存器都是靜態的,即function中的局部暫存器在function的多個調用之間保持他們的值。

  任務(task)類似於一般編程語言中的Process(過程),它可以從描述的不同位置執行共同的代碼。通常把需要共用的代碼段定義為task,然後通過task調用來使用它。在task中還可以調用其他的taskfunction
  task的定義
  task<任務名>
    埠與類型說明;
    變數聲明;
    語句1
    。。。
    語句n
  endtask
  在定義一個task時,必須注意以下幾點:
  (1):  任務定義結構不能出現在任何一個過程塊內;
  (2):  一個task可以沒有輸入/輸出埠,當然也可以有;
  (3):  一個task可以沒有返回值,也可以通過輸出埠或雙向埠返回一個或多個值;
  (4):  除任務參數外,task還能夠引用說明任務的模組中定義的任何變數;
  task的調用:
  task調用語句給出傳入任務的參數值和接收結果的變數值,
    <任務名>  (1,埠2... ,埠n);
  在調用task時,必須注意一下幾點:
  (1):  task調用是過程性語句,因此只能出現在always過程塊和initial過程塊中,調用task的輸入與輸出參數必須是寄存器類型的;
  (2):  task調用語句中的列表必須與任務定義時的輸入、輸出和雙向埠參數說明的順序相匹配。
  (3):  在調用task時,參數要按值傳遞,而不能按位址傳遞(和其他語言的不同)
  (4):  在一個task中,可也直接訪問上一級調用模組中的任何寄存器;
  (5):  可以使用迴圈中斷控制語句disable來中斷任務執行,在task被中斷後,程式流程將返回到調用task調用的地方繼續向下執行。

  taskfunction的不同點:
  (1):  function只能與主模組共用一個仿真時間單位,而task可以定義自己的仿真時間單位;
  (2):  function不能調用任務,而task可以調用函數;
  (3):  function至少需要一個輸入變數,而task可以沒有或者有很多個任意類型的變數;
  (4):  function返回一個值,而task則不返回值;

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...