跳轉到

第2章 微運算

簡介

微運算是一種對暫存器內資料進行操作的基本運算。可以分成以下四類微運算

  • 資料傳遞微運算( microoperation)
  • 「算術微運算」(arithmetic microoperation)
  • 「邏輯微運算」(logic microoperation)
  • 「移位微運算」(shift microoperation)

資料傳遞微運算

算術微運算

四位元算術邏輯微運算,提供7種算術功能,包括加法、進位加法、減法、借位減法、遞增、遞減、轉移。

Verilog程式碼
module arithmetic_microoperation (clock, reset, s, a, b, carry, data);
    input clock, reset, carry;
    input [1:0] s;
    input signed [3:0] a, b;
    output signed [4:0] data;

    reg [4:0] data;

    always @ (posedge clock) begin
        case ({s, carry})
            0: data = a + b;
            1: data = a + b + carry;
            2: data = a + ~b;
            3: data = a + ~b + 1;
            4: data = a;
            5: data = a + 1;
            6: data = a - 1;
            7: data = a;
        endcase

    end

    always @ (posedge clock) begin
        if (reset == 1)
            data = 0;
    end

endmodule // arithmetic_microoperation
Verilog測試檔
`include "arithmetic_microoperation.v"

module arithmetic_microoperation_test ();
    reg clock, reset, carry;
    reg [1:0] s;
    reg signed [3:0] a, b;

    wire signed [4:0] data;

    integer number, number2;
    integer seed;

    arithmetic_microoperation UUT (clock, reset, s, a, b, carry, data);

    initial begin
        seed = 10;
    end
    initial begin
        $display("| clock | reset | s carry |  a |  b | data |");
        clock = 1'b1;
        reset = 1'b1;

        #10;
        #5;

        reset = 1'b0;

        #10;

        for (number = 0; number < 8; number = number + 1) begin
            for (number2 = 0; number2 < 32; number2 = number2 + 16) begin
                {s, carry} = number;
                a = $random(seed) % 16;
                b = $random(seed) % 16;
                #20;
            end
        end
        #10;
        reset = 1'b1;

        #20;
        $finish;
    end

    always begin
        #10;
        clock = ~clock;
    end

    always begin
    #10;

    $monitor(
        "|   %b   |   %b   |   %b%b   | %d | %d |   %d |",
        clock, reset, s, carry, a, b, data);

    end

endmodule // arithmetic_microoperation_test
真值表
| clock | reset | s carry |  a |  b | data |
|   0   |   1   |   xxx   |  x |  x |    0 |
|   0   |   0   |   xxx   |  x |  x |    0 |
|   1   |   0   |   xxx   |  x |  x |    0 |
|   1   |   0   |   000   |  0 |  6 |    0 |
|   0   |   0   |   000   |  0 |  6 |    0 |
|   1   |   0   |   000   |  0 |  6 |    6 |
|   1   |   0   |   000   |  4 | -3 |    6 |
|   0   |   0   |   000   |  4 | -3 |    6 |
|   1   |   0   |   000   |  4 | -3 |    1 |
|   1   |   0   |   001   |  1 | -5 |    1 |
|   0   |   0   |   001   |  1 | -5 |    1 |
|   1   |   0   |   001   |  1 | -5 |   13 |
|   1   |   0   |   001   | -7 | -3 |   13 |
|   0   |   0   |   001   | -7 | -3 |   13 |
|   1   |   0   |   001   | -7 | -3 |   -9 |
|   1   |   0   |   010   |  3 |  6 |   -9 |
|   0   |   0   |   010   |  3 |  6 |   -9 |
|   1   |   0   |   010   |  3 |  6 |   -4 |
|   1   |   0   |   010   | -2 |  2 |   -4 |
|   0   |   0   |   010   | -2 |  2 |   -4 |
|   1   |   0   |   010   | -2 |  2 |   -5 |
|   1   |   0   |   011   |  6 | -8 |   -5 |
|   0   |   0   |   011   |  6 | -8 |   -5 |
|   1   |   0   |   011   |  6 | -8 |   14 |
|   1   |   0   |   011   |  5 |  5 |   14 |
|   0   |   0   |   011   |  5 |  5 |   14 |
|   1   |   0   |   011   |  5 |  5 |    0 |
|   1   |   0   |   100   |  5 |  1 |    0 |
|   0   |   0   |   100   |  5 |  1 |    0 |
|   1   |   0   |   100   |  5 |  1 |    5 |
|   1   |   0   |   100   |  4 |  0 |    5 |
|   0   |   0   |   100   |  4 |  0 |    5 |
|   1   |   0   |   100   |  4 |  0 |    4 |
|   1   |   0   |   101   |  7 |  2 |    4 |
|   0   |   0   |   101   |  7 |  2 |    4 |
|   1   |   0   |   101   |  7 |  2 |    8 |
|   1   |   0   |   101   |  6 | -3 |    8 |
|   0   |   0   |   101   |  6 | -3 |    8 |
|   1   |   0   |   101   |  6 | -3 |    7 |
|   1   |   0   |   110   |  5 | -1 |    7 |
|   0   |   0   |   110   |  5 | -1 |    7 |
|   1   |   0   |   110   |  5 | -1 |    4 |
|   1   |   0   |   110   | -5 |  5 |    4 |
|   0   |   0   |   110   | -5 |  5 |    4 |
|   1   |   0   |   110   | -5 |  5 |   -6 |
|   1   |   0   |   111   | -6 |  7 |   -6 |
|   0   |   0   |   111   | -6 |  7 |   -6 |
|   1   |   0   |   111   | -6 |  7 |   -6 |
|   1   |   0   |   111   |  1 | -4 |   -6 |
|   0   |   0   |   111   |  1 | -4 |   -6 |
|   1   |   0   |   111   |  1 | -4 |    1 |
|   0   |   0   |   111   |  1 | -4 |    1 |
|   0   |   1   |   111   |  1 | -4 |    1 |
|   1   |   1   |   111   |  1 | -4 |    1 |
|   0   |   1   |   111   |  1 | -4 |    1 |
腳本程式
file='arithmetic_microoperation'
iverilog -o ${file}_test.vvp ${file}_test.v && vvp ${file}_test.vvp > ${file}.log

邏輯微運算

「邏輯微運算」(logic microoperation)是指用來處理暫存器內位元進行二進位邏輯運算,邏輯運算很少會用在科學計算上,但使用在邏輯決策或者二進位資料操作很快速,另外對於 CRC 或者資料驗證也是方便。

例如進行 XOR 運算時,當 P=1P = 1 ,將 R1R1R2R2 進行互斥或閘運算,將結果放回到 R1R1 ,這個過程用以下表示資料運算結果:

P:R1R1R2P: R1 \gets R1 \oplus R2

例如 R1R1 有 4 bits 的資料,與 R2R2 中的 4bits 資料進行互斥或閘運算後,所呈現的結果:

111010110101 \def\arraystretch{1} \begin{array}{} & 1110 \\ \oplus & 1011 \\ \hline & 0101 \\ \end{array}

這邊特殊符號會使用 Verilog 的表示方式,來表示不同的呈現,例如使用。

邏輯微運算

「布林函數」(bool function) 微運算 命名
F0=0F_0 = 0 F0F \gets 0 清除
F1=xyF_1 = xy FA&BF \gets A \& B
F2=xyF_2 = xy' FAF \gets A 轉移 A
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B
F1=xyF_1 = xy FA&BF \gets A \& B

「硬體實現」(hardware implementation)上雖然有16種變化需要使用與製作,但此次實務上不會一次全部製作與呈現,而是製作基礎的 及閘、或閘、互斥或閘、反閘來實現,透過多次反覆運算暫存器內的資料也可以達到相同的結果。

以下是我們實際設計的電路:

Verilog程式碼
module logic_microoperation (
    clock, reset, selective_set, processor_register, b_in, data);
input clock, reset;
input [1:0] selective_set;
input [3:0] processor_register, b_in;
output [3:0] data;

reg [3:0] data;

always @ (posedge clock) begin
    case (selective_set)
        0: data = processor_register & b_in;
        1: data = processor_register | b_in;
        2: data = processor_register ^ b_in;
        3: data = ~processor_register;
    endcase
end

always @ (posedge clock) begin
    if (reset == 1)
        data = 0;
end

endmodule // logic_microoperation
Verilog測試檔
`include "logic_microoperation.v"

module logic_microoperation_test ();
    reg clock, reset, carry;
    reg [1:0] selective_set;
    reg signed [3:0] processor_register, b_in;

    wire signed [3:0] data;

    integer number, number2;
    integer seed;

    logic_microoperation UUT (clock, reset, selective_set, processor_register, b_in, data);

    initial begin
        seed = 10;
    end
    initial begin
        $display("| clock | reset | selective_set | processor_register | b_in | data |");
        clock = 1'b1;
        reset = 1'b1;

        #10;
        #5;

        reset = 1'b0;

        #10;

        for (number = 0; number < 8; number = number + 1) begin
            for (number2 = 0; number2 < 32; number2 = number2 + 16) begin
                selective_set = number;
                processor_register = $random(seed) % 16;
                b_in = $random(seed) % 16;
                #20;
            end
        end
        #10;
        reset = 1'b1;

        #40;
        $finish;
    end

    always begin
        #10;
        clock = ~clock;
    end

    always begin
    #10;

    $monitor(
        "|   %b   |   %b   |   %b   | %b | %b |  %b |",
        clock, reset, selective_set, processor_register, b_in, data);

    end

endmodule // logic_microoperation_test
真值表
| reset | selective_set | processor_register | b_in | data |
|   0   |   00   | 0100 | 1101 |  0000 |
|   0   |   01   | 0001 | 1011 |  0100 |
|   0   |   10   | 0011 | 0110 |  0101 |
|   0   |   11   | 0101 | 0101 |  1010 |
|   1   |   xx   | xxxx | xxxx |  0000 |
模擬結果
| clock | reset | selective_set | processor_register | b_in | data |
|   0   |   1   |   xx   | xxxx | xxxx |  0000 |
|   0   |   0   |   xx   | xxxx | xxxx |  0000 |
|   1   |   0   |   xx   | xxxx | xxxx |  0000 |
|   1   |   0   |   00   | 0000 | 0110 |  0000 |
|   0   |   0   |   00   | 0000 | 0110 |  0000 |
|   1   |   0   |   00   | 0000 | 0110 |  0000 |
|   1   |   0   |   00   | 0100 | 1101 |  0000 |
|   0   |   0   |   00   | 0100 | 1101 |  0000 |
|   1   |   0   |   00   | 0100 | 1101 |  0100 |
|   1   |   0   |   01   | 0001 | 1011 |  0100 |
|   0   |   0   |   01   | 0001 | 1011 |  0100 |
|   1   |   0   |   01   | 0001 | 1011 |  1011 |
|   1   |   0   |   01   | 1001 | 1101 |  1011 |
|   0   |   0   |   01   | 1001 | 1101 |  1011 |
|   1   |   0   |   01   | 1001 | 1101 |  1101 |
|   1   |   0   |   10   | 0011 | 0110 |  1101 |
|   0   |   0   |   10   | 0011 | 0110 |  1101 |
|   1   |   0   |   10   | 0011 | 0110 |  0101 |
|   1   |   0   |   10   | 1110 | 0010 |  0101 |
|   0   |   0   |   10   | 1110 | 0010 |  0101 |
|   1   |   0   |   10   | 1110 | 0010 |  1100 |
|   1   |   0   |   11   | 0110 | 1000 |  1100 |
|   0   |   0   |   11   | 0110 | 1000 |  1100 |
|   1   |   0   |   11   | 0110 | 1000 |  1001 |
|   1   |   0   |   11   | 0101 | 0101 |  1001 |
|   0   |   0   |   11   | 0101 | 0101 |  1001 |
|   1   |   0   |   11   | 0101 | 0101 |  1010 |
|   1   |   0   |   00   | 0101 | 0001 |  1010 |
|   0   |   0   |   00   | 0101 | 0001 |  1010 |
|   1   |   0   |   00   | 0101 | 0001 |  0001 |
|   1   |   0   |   00   | 0100 | 0000 |  0001 |
|   0   |   0   |   00   | 0100 | 0000 |  0001 |
|   1   |   0   |   00   | 0100 | 0000 |  0000 |
|   1   |   0   |   01   | 0111 | 0010 |  0000 |
|   0   |   0   |   01   | 0111 | 0010 |  0000 |
|   1   |   0   |   01   | 0111 | 0010 |  0111 |
|   1   |   0   |   01   | 0110 | 1101 |  0111 |
|   0   |   0   |   01   | 0110 | 1101 |  0111 |
|   1   |   0   |   01   | 0110 | 1101 |  1111 |
|   1   |   0   |   10   | 0101 | 1111 |  1111 |
|   0   |   0   |   10   | 0101 | 1111 |  1111 |
|   1   |   0   |   10   | 0101 | 1111 |  1010 |
|   1   |   0   |   10   | 1011 | 0101 |  1010 |
|   0   |   0   |   10   | 1011 | 0101 |  1010 |
|   1   |   0   |   10   | 1011 | 0101 |  1110 |
|   1   |   0   |   11   | 1010 | 0111 |  1110 |
|   0   |   0   |   11   | 1010 | 0111 |  1110 |
|   1   |   0   |   11   | 1010 | 0111 |  0101 |
|   1   |   0   |   11   | 0001 | 1100 |  0101 |
|   0   |   0   |   11   | 0001 | 1100 |  0101 |
|   1   |   0   |   11   | 0001 | 1100 |  1110 |
|   0   |   0   |   11   | 0001 | 1100 |  1110 |
|   0   |   1   |   11   | 0001 | 1100 |  1110 |
|   1   |   1   |   11   | 0001 | 1100 |  1110 |
|   0   |   1   |   11   | 0001 | 1100 |  1110 |
|   1   |   1   |   11   | 0001 | 1100 |  0000 |
|   0   |   1   |   11   | 0001 | 1100 |  0000 |
腳本程式
file='logic_microoperation'
iverilog -o ${file}_test.vvp ${file}_test.v && vvp ${file}_test.vvp > ${file}.log

移位微運算