算術邏輯單元的實現(ALU)

2023-09-01 18:00:49

一、實驗目的

  • 掌握Vivado整合式開發環境
  • 掌握Verilog語言基本知識、
  • 掌握並理解算術邏輯單元ALU的原理和設計

二、實驗預習

1.ALU(算術邏輯單元)的16種運算的編碼

三、模組介面設計

ALU的訊號說明如下:

  • 定義四個輸入訊號A、B、Cin、Card。其中,A、B為32位元運算數,Card為5位運算操作碼,Cin為進位。
  • 定義三個輸出訊號F,Cout,Zero,其中F為運算結果,Cout為結果進位,Zero為零標誌。
  • 要求根據16種運算操作對運算操作碼Card進行編碼,並實現這16種運算操作。

四、實驗設計

設計程式碼

`define A_ADD_B         5'b00001 // A 加 B
`define A_ADD_B_ADD_CIN 5'b00010 // A 加 B 加 Cin
`define A_SUB_B         5'b00011 // A 減 B 減 
`define A_SUB_B_SUB_CIN 5'b00100 // A 減 B 減 Cin
`define B_SUB_A         5'b00101 // B 減 A
`define B_SUB_A_SUB_CIN 5'b00110 // B 減 A 減 Cin
`define VALUE_A         5'b00111 // F = A
`define VALUE_B         5'b01000 // F = B
`define NOT_A           5'b01001 // F = /A
`define NOT_B           5'b01010 // F = /B
`define A_OR_B          5'b01011 // F = A + B
`define A_AND_B         5'b01100 // F = AB
`define A_XNOR_B        5'b01101 // 同或
`define A_XOR_B         5'b01110 // 互斥或
`define A_NAND_B        5'b01111 // F = /(AB)
`define ZERO_FLAG       5'b10000 // F = 0

module alu (
    input  [31:0]   A   ,
    input  [31:0]   B   ,
    input           Cin ,
    input  [4 :0]   Card,
    
    output [31:0]   F   ,
    output          Cout,
    output          Zero
);
    
    wire [31:0]    a_add_b_result;
    wire [31:0]    a_add_b_add_cin_result;
    wire [31:0]    a_sub_b_result;
    wire [31:0]    a_sub_b_sub_cin_result;
    wire [31:0]    b_sub_a_result;
    wire [31:0]    b_sub_a_sub_cin_result;
    wire [31:0]    value_a_result;
    wire [31:0]    value_b_result;
    wire [31:0]    not_a_result;
    wire [31:0]    not_b_result;
    wire [31:0]    a_or_b_result;
    wire [31:0]    a_and_b_result;
    wire [31:0]    a_xnor_b_result;
    wire [31:0]    a_xor_b_result;
    wire [31:0]    a_nand_b_result;
    wire [31:0]    zero_flag_result;
    
    // 6 個進位
    wire cout_1;
    wire cout_2;
    wire cout_3;
    wire cout_4;
    wire cout_5;
    wire cout_6;
    // 16 種運算
    assign {cout1, a_add_b_result} = A + B;
    assign {cout2, a_add_b_add_cin_result} = A + B + Cin;
    assign {cout3, a_sub_b_result} = A - B;
    assign {cout4, a_sub_b_sub_cin_result} = A - B - Cin;
    assign {cout5, b_sub_a_result} = B - A;
    assign {cout6, b_sub_a_sub_cin_result} = B - A - Cin;
    assign value_a_result = A;
    assign value_b_result = B;
    assign not_a_result = ~A;
    assign not_b_result = ~B;
    assign a_or_b_result = A | B;
    assign a_and_b_result = A & B;
    assign a_xnor_b_result = ~(A ^ B);
    assign a_xor_b_result = A ^ B;
    assign a_nand_b_result = ~(A & B);
    assign zero_flag_result = 0;
    
    // 運算結果 依據操作碼Card選擇
    assign  F   =   ({32{Card == `A_ADD_B}}  & a_add_b_result)  |
                    ({32{Card == `A_ADD_B_ADD_CIN}}  & a_add_b_add_cin_result)  |
                    ({32{Card == `A_SUB_B}}  & a_sub_b_result)  |
                    ({32{Card == `A_SUB_B_SUB_CIN}} & a_sub_b_sub_cin_result) |
                    ({32{Card == `B_SUB_A}} & b_sub_a_result) |
                    ({32{Card == `B_SUB_A_SUB_CIN}} & b_sub_a_sub_cin_result) |
                    ({32{Card == `VALUE_A}} & value_a_result) |
                    ({32{Card == `VALUE_B}} & value_b_result) |
                    ({32{Card == `NOT_A}} & not_a_result) |
                    ({32{Card == `NOT_B}} & not_b_result) |
                    ({32{Card == `A_OR_B}} & a_or_b_result) |
                    ({32{Card == `A_AND_B}} & a_and_b_result) |
                    ({32{Card == `A_XNOR_B}} & a_xnor_b_result) |
                    ({32{Card == `A_XOR_B}} & a_xor_b_result) |
                    ({32{Card == `A_NAND_B}} & a_nand_b_result) |
                    ({32{Card == `ZERO_FLAG}} & zero_flag_result) | 
                    0;
    // 進位標誌
    assign  Cout =  ({Card == `A_ADD_B}  & cout1)  |
                    ({Card == `A_ADD_B_ADD_CIN}  & cout2)  |
                    ({Card == `A_SUB_B}  & cout3)  |
                    ({Card == `A_SUB_B_SUB_CIN} & cout4) |
                    ({Card == `B_SUB_A} & cout5) |
                    ({Card == `B_SUB_A_SUB_CIN} & cout6) |
                    0; 
    // 0標誌,F為0時為1
    assign  Zero =  (F == 0) | 0;

endmodule

模擬程式碼

`timescale 1ns / 1ps
module sim();
    reg [31:0] A;
    reg [31:0] B;
    reg Cin;
    reg [4:0] Card;
    wire Cout;
    wire [31:0] F;
    wire Zero;
    
    initial begin
        Card = 5'b00000;
        A = 32'h0000_0000;
        B = 32'h0000_0000;
        Cin = 1'b0;
        
        #10 // F = A 加 B
        Card = 5'b00001;
        A = 32'hffff_ffff;
        B = 32'h0000_0001;
        Cin = 1'b1;
        
        #10 // F = A 加 B 加 Cin
        Card = 5'b00010;
        A = 32'hffff_ffff;
        B = 32'h0000_0001;
        Cin = 1'b1;
        
        #10 // F = A 減 B
        Card = 5'b00011;
        A = 32'h0000_0001;
        B = 32'h0000_0002;
        Cin = 1'b1;
        
        #10 // F = A 減 B 減 Cin
        Card = 5'b00100;
        A = 32'h0000_0001;
        B = 32'h0000_0002;
        Cin = 1'b1;
        
        #10 // F = B 減 A
        Card = 5'b00101;
        A = 32'h0000_0002;
        B = 32'h0000_0001;
        Cin = 1'b1;
        
        #10 // F = B 減 A 減 Cin
        Card = 5'b00110;
        A = 32'h0000_0002;
        B = 32'h0000_0001;
        Cin = 1'b1;
        
        #10 // F = A
        Card = 5'b00111;
        A = 32'h0000_0002;
        B = 32'h0000_0001;
        
        #10 // F = B
        Card = 5'b01000;
        A = 32'h0000_0002;
        B = 32'h0000_0001;
        
        #10 // F = /A
        Card = 5'b01001;
        A = 32'h0000_0001;
        
        #10 // F = /B
        Card = 5'b01010;
        B = 32'h0000_0002;
        
        #10 // F = A + B
        Card = 5'b01011;
        A = 32'h0000_0001;
        B = 32'hffff_fff0;
        
        #10 // F = AB
        Card = 5'b01100;
        A = 32'h0000_0001;
        B = 32'hffff_ffff;
        
        #10 // F = A XNOR B
        Card = 5'b01101;
        A = 32'h0000_f0f0;
        B = 32'h0f0f_0000;
        
        #10 // F = A XOR B
        Card = 5'b01110;
        A = 32'h0000_f0f0;
        B = 32'h0f0f_0000;
        
        #10 // F = /(AB)
        Card = 5'b01111;
        A = 32'h0808_f0f0;
        B = 32'h0f0f_8888;
        
        #10 // F = 0
        Card = 5'b10000;
        
        #10 Card = 5'b10010;
        #10 Card = 5'b10010;
        #10 Card = 5'b10011;
        #10 Card = 5'b10100;
        #10 Card = 5'b10101;
        #10 Card = 5'b10110;
        #10 Card = 5'b10111;
        #10 Card = 5'b11000;
        #10 Card = 5'b11001;
        #10 Card = 5'b11010;
        #10 Card = 5'b11011;
        #10 Card = 5'b11100;
        #10 Card = 5'b11101;
        #10 Card = 5'b11110;
        #10 Card = 5'b11111;
    end
    
    alu u0 (
        .A(A),
        .B(B),
        .Cin(Cin),
        .Card(Card),
        .F(F),
        .Cout(Cout),
        .Zero(Zero)
    );
endmodule

五、測試結果及實驗分析

測試波形

運算功能 A(H) B(H) Cin 操作碼 (五位) F(H) Zero
F=A加B FFFF_FFFF 0000_0001 1 00001 0000_0000 1
F=A加B加Cin FFFF_FFFF 0000_0001 1 00010 0000_0001 0
F=A減B 0000_0001 0000_0002 1 00011 FFFF_FFFF 0
F=A減B減Cin 0000_0001 0000_0002 1 00100 FFFF_FFFE 0
F=B減A 0000_0002 0000_0001 1 00101 FFFF_FFFF 0
F= B減A減Cin 0000_0002 0000_0001 1 00110 FFFF_FFFE 0
F=A 0000_0002 0000_0001 1 00111 0000_0002 0
F=B 0000_0002 0000_0001 1 01000 0000_0001 0
F=/A 0000_0001 0000_0001 1 01001 FFFF_FFFE 0
F=/B 0000_0001 0000_0002 1 01010 FFFF_FFFD 0
F=A+B 0000_0001 FFFF_FFF0 1 01011 FFFF_FFF1 0
F=AB 0000_0001 FFFF_FFFF 1 01100 0000_0001 0
F=A⊙B 0000_F0F0 0F0F_0000 1 01101 F0F0_0F0F _ _ 0
F=A⊕B 0000_F0F0 0F0F_0000 1 01110 0F0F_F0F0 0
F=/(AB) 0808_F0F0 0F0F_8888 1 01111 F7F7_7F7F 0
F=0 0808_F0F0 0F0F_8888 1 10000 0000_0000 1

實驗結果分析:

對比實驗結果與正確運算結果,實驗結果符合預期。在前6個算術運算操作中,進位訊號Cout表現正確。

比如在第2個「F=A加B加Cin」操作中,選取的例子為「A = ffff_ffffH, B = 0000_0001H, Cin = 1」,結果應為進1位,和為0000_0001H,結果正確。

邏輯運算中,測試用例較為複雜,如操作15與非運算,「A = 0808_f0f0H, B = 0f0f_8888H, F = f7f7_7f7fH」,結果正確。當運算操作碼無效時,結果輸出0。

六、實驗總結

本次實驗利用Vivado開發環境和Verilog硬體描述語言實現了一個簡單的算術邏輯單元。通過本次實驗,我們鞏固了所學的數位邏輯知識,鍛鍊了硬體思維,提高了自身動手能力。