天天看點

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

目錄

  • 0 前言
    • 0.1 使用環境
    • 0.2 知識點
    • 0.3 注意事項
  • 1 模組化:1位加法器
    • 1.1 建構基礎模型
      • 1.1.1 一位加法器
        • 1.1.1.1 科技黑箱:外部端口與功能
        • 1.1.1.2 揭秘黑箱:内部結構與子產品
      • 1.1.2 從頂層子產品提取低層子產品:取反功能選擇器
        • 1.1.2.1 科技黑箱:外部端口與功能
        • 1.1.2.2 揭秘黑箱:内部結構與子產品
      • 1.1.3 從頂層子產品提取低層子產品:基礎加法器
        • 1.1.3.1 科技黑箱:外部端口與功能
        • 1.1.3.2 揭秘黑箱:内部結構與子產品
    • 1.2 層次模組化
      • 1.2.1 32位加法器
      • 1.2.2 1位加法器
  • 2 實作:1位加法器
    • 2.1 取反選擇器
      • 2.1.1 設計塊
      • 2.1.2 激勵塊
      • 2.1.3 功能驗證
    • 2.2 基礎加法器
      • 2.2.1 設計塊
      • 2.2.2 激勵塊
      • 2.2.3 功能驗證
    • 2.3 1位加法器的實作
      • 2.3.1 設計塊
      • 2.3.2 激勵塊&功能驗證
  • 3 原理講解:實作整數減法,将負數轉換為補碼
    • 3.1 計算機進制數與人類進制數的差别
      • 3.1.1 十進制數轉換為補碼的原理
    • 3.2 進位輸入信号carry_in的作用
  • 3 模組化:32位加法器
    • 3.1 科技黑箱:外部端口
    • 3.2 揭秘黑箱:内部細節
      • 3.2.1 組合式設計的核心原則
  • 4 實作:32位加法器
    • 4.1 設計塊
    • 4.2 激勵塊
      • 4.2.1 報錯解決方案
    • 4.3 仿真驗證
  • 5 行為級模組化的魅力
    • 5.1 設計塊
    • 5.2 激勵塊
    • 5.3 結果驗證
    • 5.4 思考點
  • 6 由行為級描述掌握幾大重要思想
  • 7 待求解決方案的錯誤

0 前言

0.1 使用環境

  • EDA工具:Vivado 2017.4
  • 硬體描述語言:Verilog HDL

0.2 知識點

  • 加法器(全加器)
  • 多路選擇器
  • Verilog 語言及其設計思想
  • 補碼

0.3 注意事項

本文中所有的Verilog實作部分,均完成了仿真測試,并未進行時序驗證以及後續的邏輯綜合步驟,後續步驟可能會出現問題,請讀者自行完成修改。

1 模組化:1位加法器

我們先來建構1位加法器,要知道,32位加法器隻不過是将32個1位加法器以特定的方式連接配接起來,真正的核心是1位加法器的設計。

1.1 建構基礎模型

1.1.1 一位加法器

1.1.1.1 科技黑箱:外部端口與功能

功能:能夠實作整數的加減法,這也就意味着

  1. 支援正數和負數,支援加法和減法(事實上,a+(-b) = a - b;負數與減法某種程度上來說,是一樣的)
  2. 能夠識别正負數,并且能夠做出不同的選擇
    1. 遇到正數、加法,直接運算
    2. 遇到負數、減法 ,轉換為補碼再運算
【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤
  • 輸入端口
    • 資料:a,b
    • 進位:carry_in
    • 取反控制:a_invert,b_invert
  • 輸出端口
    • 和:sum
    • 進位:carry_out

特别注意:對于多個加法器組合的情況,carry_in是來自上一個加法器的carry_out,如果位置是第一個,則要置為0

1.1.1.2 揭秘黑箱:内部結構與子產品

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

内部線網:不與外部相連的内部線,就是内部線網,在Verilog設計中需要單獨加上!

1.1.2 從頂層子產品提取低層子產品:取反功能選擇器

1.1.2.1 科技黑箱:外部端口與功能

下圖圖示部分為取反功能選擇器,其功能是控制輸入的資料是否執行取反操作

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

以下是其外部端口:

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

1.1.2.2 揭秘黑箱:内部結構與子產品

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

多路選擇器的全面講解參考我的另一篇文章:全面剖析資料選擇器

1.1.3 從頂層子產品提取低層子產品:基礎加法器

1.1.3.1 科技黑箱:外部端口與功能

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

1.1.3.2 揭秘黑箱:内部結構與子產品

使用資料流模組化,兩個邏輯表達式就可以,這個部分是數字邏輯必備知識,不再贅述。

1.2 層次模組化

1.2.1 32位加法器

1.2.2 1位加法器

2 實作:1位加法器

2.1 取反選擇器

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

2.1.1 設計塊

`timescale 1ns / 1ps

// 取反選擇器的設計
module date_invert_choose (
    input a,            // 資料輸入
    input a_invert,     // 使能端         
    output a_out        // 資料輸出
    );
    
    choose_2to1 CH0 (a,~a,a_invert,a_out);  // 調用二選一選擇器執行個體
    
endmodule

// 二選一選擇器
module choose_2to1 (
    input d0,d1,    // 資料輸入
    input add,      // 位址控制
    output out      // 資料輸出
    );
    
    assign out = (~add)&d0 | add&d1;
    
endmodule
           

FPGA優化結果如下:

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

2.1.2 激勵塊

設定激勵塊有兩個口訣:

  • 調用子產品,建執行個體
  • 設定輸入,驗輸出
`timescale 1ns / 1ps

module test;

    // 設定變量
    reg a;          // 資料輸入
    reg a_invert;   // 控制輸入
    wire a_out;     // 資料輸出       
    
    // 調用執行個體【調用子產品建執行個體】
    date_invert_choose DIC0 (a,a_invert,a_out); // 【不要忘了執行個體名!隻有門級描述可以不寫】
    
    // 設定信号【設定輸入,看輸出】
    initial
    begin
        a = 1;
    
        a_invert = 0;
        #1 $display("功能%b,直接輸出:a_out = %b\n",a_invert,a_out);
        
        a_invert = 1;
        #1 $display("功能%b,取反輸出:a_out = %b\n",a_invert,a_out);
    end
    
endmodule
           

2.1.3 功能驗證

仿真結果沒有問題!

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

2.2 基礎加法器

2.2.1 設計塊

module add_base_1size (
    input a,b,          // 資料輸入
    input carry_in,     // 進位輸入
    output carry_out,   // 進位輸出
    output sum          // 和
    );
    
    assign sum = a ^ b ^ carry_in;
    assign carry_out = a&b | (a^b)&carry_in;

endmodule
           

2.2.2 激勵塊

請讀者自行完成

2.2.3 功能驗證

經過仿真驗證,沒有問題。

2.3 1位加法器的實作

本節展現的是完整代碼,包含2.1和2.2的設計塊代碼

【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

2.3.1 設計塊

`timescale 1ns / 1ps

// 取反選擇器的設計
module date_invert_choose (
    input a,            // 資料輸入
    input a_invert,     // 使能端         
    output a_out        // 資料輸出
    );
    
    choose_2to1 CH0 (a,~a,a_invert,a_out);  // 調用二選一選擇器執行個體
    
endmodule

// 二選一選擇器
module choose_2to1 (
    input d0,d1,    // 資料輸入
    input add,      // 位址控制
    output out      // 資料輸出
    );
    
    assign out = (~add)&d0 | add&d1;
    
endmodule

// 基礎加法器
module add_base_1size (
    input a,b,          // 資料輸入
    input carry_in,     // 進位輸入
    output carry_out,   // 進位輸出
    output sum          // 和
    );
    
    assign sum = a ^ b ^ carry_in;
    assign carry_out = a&b | (a^b)&carry_in;

endmodule

// 1位加法器的實作
module add_1size (
    input a,b,      // 資料輸入
    input a_invert,b_invert,    //  求反控制
    input carry_in,     
    output carry_out,
    output sum
    );
    
    // 内部線網設定
    wire a_out,b_out;   // 獲得經過求反選擇器之後的結果
    
    // 調用子產品執行個體
    
    // 求反控制器執行個體
    date_invert_choose DateA (a,a_invert,a_out);
    date_invert_choose DateB (b,b_invert,b_out);
    // 加法器執行個體
    add_base_1size Add_A_B (a_out,b_out,carry_in,carry_out,sum);
    
endmodule
           

2.3.2 激勵塊&功能驗證

module test;

    reg a,b;    // 注意reg為無符号數
    reg a_invert,b_invert;
    reg carry_in;
    wire carry_out;
    wire sum;

    add_1size AD0 (a,b,a_invert,b_invert,carry_in,carry_out,sum);
    
    // 設定信号,求 a + (-b)即 a - b
    initial
    begin
        a = 0;  b = 0;
        a_invert = 0;   b_invert = 1;   // b取反
        carry_in = 1;   // b取反加1
        #1 $display("a = %b,  b = %b,  carry_out = %b\na - b = %b\n",a,b,carry_out,sum); // 模拟 a - b
        if (sum == 0)
        	$display("驗證成功! 0 - 0 = 0");
    end
    
endmodule
           
【計算機組成原理 & 數字邏輯 & Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

這裡的驗證我有必要講解一下,因為有些地方會令人費解。

  1. reg

    為無符号數,如果直接像

    reg a = -1

    這樣的文法,存到計算機中是自動以補碼形式存儲的,那樣的話就沒有辦法驗證我們的設計了。要明白的一點是,我們是假定計算機不會自動将負數轉換為補碼,由我們的設計來實作這個工作,是以,這裡我直接手動輸入了某個數的原碼,再有我們的設計将其轉換為補碼,這樣就完成了驗證工作。
  2. 我們假定

    在十進制下,a > 0,-b < 0,我們要求出 a + (-b)的值

    ,并且這台計算機沒有将-b存儲為補碼的功能,我們又知道b的二進制形式就是其補碼,它在經過全部按位取反再加1後,會得到-b的補碼,是以也就有了激勵塊中的

    b = 0;

    carry_in = 1;

    ,這是為了驗證取反加1功能是否正确。
  3. 實際的過程是這樣的:

    a + b取反 + 1 = a + (-b) = a - b

    ,這樣就是能夠讓你明白兩件事,負數的補碼轉換和減法轉換為加法它的實際過程是這樣的:

    a = 0,b = 0,故a + b取反 + 1 = 0 + 1 + 1 = 10

    也就是

    sum = 0;carry_out = 1;

3 原理講解:實作整數減法,将負數轉換為補碼

本小節可以跳過,可以看完第4節再回看。

3.1 計算機進制數與人類進制數的差别

計算機進制數指的是

  • 二進制
  • 八進制
  • 十六進制

人類進制數指的是

  • 十進制

兩者差别主要在于,十進制數使用

-

來表示負數,而計算機進制數使用補碼來表示負數,在其資料本身,就包含了符号,而十進制資料是不包含符号位的,它的符号位是單獨存在的。這也是機器數資料符号化的特點。

而人類又習慣于使用十進制,這才有了負數的補碼轉換方法及其硬體設計邏輯。

在這裡重點強調,不要理會原碼、反碼,這是曆史上已經被淘汰的東西,他們跟補碼,隻是有數學上的聯系,以及曆史原因。

但是,

從十進制數轉換為補碼

這一過程跟原碼、反碼完全沒有關系,很多教材和老師的講解都是不正确的。

我們隻需要記住以下原則:

3.1.1 十進制數轉換為補碼的原理

請注意,這裡十進制數的對象為:全體實數,包含整數和小數,他們都适用于補碼轉換規則,重要的一點差別是在計算機存儲上

  • 計算機存儲整數,直接使用補碼表示
  • 計算機存儲小數,使用的是浮點表示,關于這一點請詳細閱讀浮點運算的知識

在這裡,我們以十進制整數為例來進行說明

  • 對于正數,這個非常容易,直接使用除基取餘法即可,高位需要用0補全

    例如(假定寄存器為16位):

    200D = 0000_0000_1100_1000B

  • 對于負數,需要遵循這樣的規則:全部取反再加1

例如 -2D:

(1)先表示出2D = 0000_0000_0000_0010B

(2)再全部取反,1111_1111_1111_1101B

(3)再加1,1111_1111_1111_1110B

(4)這樣得到的結果就是 -2D的補碼

需要注意的是,此時如果高位有空餘,需要補上1,而不是0

其中,我之前提到的取反功能選擇器,就是完成了取反操作,但是還有加1操作呢?我們繼續看下一小節!

3.2 進位輸入信号carry_in的作用

我在1.1.1.1節提到過,carry_這個信号,初始需要置為0,加法器單獨存在一個的時候,它是不太重要的。

隻有多個加法器連在一起(串行進位,第3節會提及)的時候,上一級的carry_in與下一級的carry_out連接配接起來,才能發揮作用。

但是,如果初始将carry_in置為1,就能夠發揮它的作用了,它在補碼轉換過程,起到了加1的作用。

無論輸入的資料是1位還是32位,加1隻需要在最低位加1,也就是隻需要把單獨存在的,不與carry_out連接配接的caryy_in置為1,就能實作加1操作。

十進制的2:0000 0000 0000 0010
		  先取反:   1111 1111 1111 1101
		  再加1:   +                   1
		         ————————————————————————
		            1111 1111 1111 1110
       
其中:取反操作使用取反選擇器完成
	     加1操作隻需将carry_in置為1
           

這樣一來,取反選擇器與carry_in = 1緊密合作,就完成了十進制數到補碼的轉換,也就實作了整數的加減法。

備注:如果這個部分看不懂,請看完第3節再回看此節。

至此,我想你能夠了解實作整數減法的硬體設計原理了。

思考點:

這裡留一個問題給讀者思考,試想,如果采用大多數老師講解的原碼、反碼和補碼的原則去轉換補碼,硬體設計會是怎樣的?

這裡我直接給你結果分析,具體設計不再講解,自行完成。

顯然,按照這樣的方式,設計會非常複雜,而且沒有必要,既違背了硬體設計簡單性原則,也增加了數學運算的複雜度

一般老師講解的原碼、反碼和補碼的轉換方式是

  • 先求原碼,再求反碼,再求補碼

我教你的是

  • 全部取反再加1

這二者是差別就是

  • 前者教你 1 + 10 - 9 = 2
  • 後者教你: 1 + 1 = 2

對比之下,哪個更加簡潔不言而喻,事實上,這些都是人為規定,怎麼計算都可以,在數學上都說的通,但是要考慮硬體簡單性原則,後者顯然更加占優勢。

【計算機組成原理 &amp; 數字邏輯 &amp; Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

假定a,b均為非負整數,則:

a - b = a + ( b取反 + 1 )

但是事實的情況往往會更加複雜,比如:

-a - b

又如何處理?

目前從原理上能夠實作減法,但這遠遠不夠,還需要根據實際需求進一步改進,這就涉及到了将其添加到MIPS指令上,這個以後再說。

3 模組化:32位加法器

這裡采用串行進位方式進行連接配接,并非并行進位(超前進位)。

關于基礎加法器的超前進位實作,參照我的文章:全面剖析:加法器——從1位到4位,從一般加法(串行進位)到快速加法(并行進位/超前進位)【此處連結待完善】

3.1 科技黑箱:外部端口

【計算機組成原理 &amp; 數字邏輯 &amp; Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

3.2 揭秘黑箱:内部細節

【計算機組成原理 &amp; 數字邏輯 &amp; Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

3.2.1 組合式設計的核心原則

  • 全部接口都連接配接,分三大類
    • 與外部總線連接配接
    • 與外部一根線連接配接
    • 内部互相連接配接(配置内部線網,一般為數組)

4 實作:32位加法器

【計算機組成原理 &amp; 數字邏輯 &amp; Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

4.1 設計塊

此處直接使用前面設計好的1位加法器,再次強調,此處為串行進位

module add_32sizes (
    input [31:0] a,b,
    input a_invert,b_invert,
    input carry_in,
    output carry_out,
    output [31:0] sum
    );
    
    // 設定内部線網
    wire carry_out_in [30:0];   // 内部串行進位傳遞
    
    // 調用子產品執行個體
    add_1size ADD0 (a[0],b[0],a_invert,b_invert,carry_in,carry_out_in[0],sum[0]);
    add_1size ADD1 (a[1],b[1],a_invert,b_invert,carry_out_in[0],carry_out_in[1],sum[1]);
    add_1size ADD2 (a[2],b[2],a_invert,b_invert,carry_out_in[1],carry_out_in[2],sum[2]);
    add_1size ADD3 (a[3],b[3],a_invert,b_invert,carry_out_in[2],carry_out_in[3],sum[3]);
    add_1size ADD4 (a[4],b[4],a_invert,b_invert,carry_out_in[3],carry_out_in[4],sum[4]);
    add_1size ADD5 (a[5],b[5],a_invert,b_invert,carry_out_in[4],carry_out_in[5],sum[5]);
    add_1size ADD6 (a[6],b[6],a_invert,b_invert,carry_out_in[5],carry_out_in[6],sum[6]);
    add_1size ADD7 (a[7],b[7],a_invert,b_invert,carry_out_in[6],carry_out_in[7],sum[7]);
    
    add_1size ADD8 (a[8],b[8],a_invert,b_invert,carry_out_in[7],carry_out_in[8],sum[8]);
    add_1size ADD9 (a[9],b[9],a_invert,b_invert,carry_out_in[8],carry_out_in[9],sum[9]);
    add_1size ADD10 (a[10],b[10],a_invert,b_invert,carry_out_in[9],carry_out_in[10],sum[10]);
    add_1size ADD11 (a[11],b[11],a_invert,b_invert,carry_out_in[10],carry_out_in[11],sum[11]); 
    add_1size ADD12 (a[12],b[12],a_invert,b_invert,carry_out_in[11],carry_out_in[12],sum[12]);
    add_1size ADD13 (a[13],b[13],a_invert,b_invert,carry_out_in[12],carry_out_in[13],sum[13]);
    add_1size ADD14 (a[14],b[14],a_invert,b_invert,carry_out_in[13],carry_out_in[14],sum[14]);
    add_1size ADD15 (a[15],b[15],a_invert,b_invert,carry_out_in[14],carry_out_in[15],sum[15]);
    
    add_1size ADD16 (a[16],b[16],a_invert,b_invert,carry_out_in[15],carry_out_in[16],sum[16]);
    add_1size ADD17 (a[17],b[17],a_invert,b_invert,carry_out_in[16],carry_out_in[17],sum[17]);
    add_1size ADD18 (a[18],b[18],a_invert,b_invert,carry_out_in[17],carry_out_in[18],sum[18]);
    add_1size ADD19 (a[19],b[19],a_invert,b_invert,carry_out_in[18],carry_out_in[19],sum[19]);
    add_1size ADD20 (a[20],b[20],a_invert,b_invert,carry_out_in[19],carry_out_in[20],sum[20]);
    add_1size ADD21 (a[21],b[21],a_invert,b_invert,carry_out_in[20],carry_out_in[21],sum[21]);
    add_1size ADD22 (a[22],b[22],a_invert,b_invert,carry_out_in[21],carry_out_in[22],sum[22]);
    add_1size ADD23 (a[23],b[23],a_invert,b_invert,carry_out_in[22],carry_out_in[23],sum[23]);
    
    add_1size ADD24 (a[24],b[24],a_invert,b_invert,carry_out_in[23],carry_out_in[24],sum[24]);
    add_1size ADD25 (a[25],b[25],a_invert,b_invert,carry_out_in[24],carry_out_in[25],sum[25]);
    add_1size ADD26 (a[26],b[26],a_invert,b_invert,carry_out_in[25],carry_out_in[26],sum[26]);
    add_1size ADD27 (a[27],b[27],a_invert,b_invert,carry_out_in[26],carry_out_in[27],sum[27]);
    add_1size ADD28 (a[28],b[28],a_invert,b_invert,carry_out_in[27],carry_out_in[28],sum[28]);
    add_1size ADD29 (a[29],b[29],a_invert,b_invert,carry_out_in[28],carry_out_in[29],sum[29]);
    add_1size ADD30 (a[30],b[30],a_invert,b_invert,carry_out_in[29],carry_out_in[30],sum[30]);
    add_1size ADD31 (a[31],b[31],a_invert,b_invert,carry_out_in[30],carry_out,sum[31]);
    
endmodule
           

4.2 激勵塊

注意,因為在Verilog中,

reg

自動以二進制補碼形式存儲,是以此處驗證負數的時候,我們假定計算機沒有以補碼存儲這一功能,我們假定

b = -5

,并且手動設定b的值,将b的值設定為5的補碼,5的補碼就是其二進制表示0101B,以此來驗證5的補碼經過全部取反加1後,是否變成了-5的補碼,進而驗證了設計的正确性。

如果你沒有看懂,那麼請看完第6節的補充連結,再回顧此内容。

module test;

    reg [31:0] a,b;    // 注意reg為無符号數
    reg a_invert,b_invert;
    integer carry_in;
    wire carry_out;
    wire [31:0] sum;

    add_32sizes AD0 (a,b,a_invert,b_invert,carry_in,carry_out,sum);
    
    // 設定信号,假設b = -5;a = 8;求a + b 
    initial
    begin
        a = 4'b1000;    // 8的補碼
        b = 4'b0101;    // reg為無符号數,自動把-5存為補碼,無法驗證結果,是以使用 |-5| = 5 的補碼
        a_invert = 0;   b_invert = 1;   // b取反
        carry_in = 1;   // b取反加1
        #1 $display("a = %d,  b = -%d\na + b = %d\n",a,b,sum); // 模拟 a - b
        if(sum == 3)
            $display("驗證成功! 8 + (- 5) = 3");
    end
    
endmodule
           

4.2.1 報錯解決方案

對于這樣的錯誤:

[XSIM 43-3238] Failed to link the design.

通常情況下,是因為激勵塊與設計塊的連接配接出了問題,可能是

  • 子產品調用錯誤
  • 子產品忘記執行個體化
  • 子產品接口連接配接錯誤

可以按照這個思路依次排查

4.3 仿真驗證

【計算機組成原理 &amp; 數字邏輯 &amp; Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

5 行為級模組化的魅力

前面說了那麼多,其實,真正硬體程式設計的時候沒有那麼麻煩,強大的EDA工具讓我們能夠隻需要描述其行為,就能完成設計,這是抽象層次足夠高的設計,讓我們來看一下。

這裡你可能想要摔電腦了,什麼????我做了這麼半天,實際上隻需要幾行??那你寫了這麼多有啥用!!

冷靜一下,仔細想一下,你是不是在之前的操作中,對于加法器已經非常熟悉了?如果你認真做了,我想應該是的,這就是Learning by doing,在做中學,能夠快速掌握知識,加深對于知識的了解程度,這一點是很必要的,是以你必須花時間來完成它。

5.1 設計塊

module add_32bits(
    input [31:0] a,b,
    input ADDctl,   // 控制端,用于識别加減法 0代表加法,1代表減法
    output reg [31:0] result
    );
    
    always @(a,b,ADDctl)
    begin
        case(ADDctl)
            0: result = a + b;
            1: result = a - b;
        endcase
    end
    
endmodule
           

5.2 激勵塊

module test;

    // reg signed [31:0] a,b;
    integer a,b;
    reg ADDctl;
    wire signed [31:0] result;
    
    add_32bits ADD_0 (a,b,ADDctl,result);
    
    initial
    begin
        // 測試加法
        a = -1;  b = 20;     
        ADDctl = 0;
        #1 $display("%d + %d = %d",a,b,result);
        #1
        // 測試減法  【1-20= 溢出值,因為不識别補碼!???怎麼辦】
        a = -10;  b = 28;     
        ADDctl = 1;
        #1 $display("%d - %d = %d",a,b,result);
    end
    
endmodule
           

5.3 結果驗證

【計算機組成原理 &amp; 數字邏輯 &amp; Verilog】32位加法器的實作:支援整數的加減運算0 前言1 模組化:1位加法器2 實作:1位加法器3 原理講解:實作整數減法,将負數轉換為補碼3 模組化:32位加法器4 實作:32位加法器5 行為級模組化的魅力6 由行為級描述掌握幾大重要思想7 待求解決方案的錯誤

5.4 思考點

  1. reg類型将負數以補碼存儲,實作了減法變為加法,那麼Verilog中為何還有減法運算?
  2. Verilog中負數以補碼形式存儲,令其以

    %d

    形式輸出的時候,并不會顯示負數,而是顯示一個超大的正數,如何解決?
  3. 如何正确顯示激勵塊輸入的負數,輸入端口的reg類型,可否使用

    integer

    類型?

以上問題,看完下一小結的擴充連結,你就能得知答案。

6 由行為級描述掌握幾大重要思想

設計的思想有

  • 分治思想
  • 歸一思想
  • 實戰驗證思維
  • 查閱資料的能力

我單獨寫了一篇文章,以闡述一些重要的理論和思想。請看:待完善

7 待求解決方案的錯誤

[XSIM 43-3345] Unable to remove previous simulation file xsim.dir/test_behav/xsimk.exe. Please check if you have another instance of this simulation running on your system, terminate it and then recompile your design. System Error Message: boost::filesystem::status: 拒絕通路。: "xsim.dir/test_behav/xsimk.exe".

[XSIM 43-3238] Failed to link the design.

我不知道為什麼會拒絕通路,并且此狀态下,系統不能删除檔案,唯一的辦法就是重建立立一個檔案,并且将設計塊和激勵塊copy過去。

問題待解決中!如有讀者知道解決方案,歡迎私聊我~

繼續閱讀