Altifigence Academy

51 / 63 · 概念

ALU 與 zero、negative、carry、overflow 旗標

以共用加法器實作 ADD/SUB,區分 carry 與 signed overflow,推導比較條件。

先備知識:二補數二補數以固定寬度的位元序列表示帶符號整數。n 位元範圍為 −2^(n−1) 至 2^(n−1)−1。 詳細內容、加法器、組合 MUX多工器是依選擇訊號,將多個輸入之一連至輸出的組合電路。必須明確定義選擇位元與輸入編號的對應關係。 詳細內容 與位元寬度擴展。

同時產生結果與狀態的 ALU

ALU 選擇各運算電路的結果,並輸出解讀結果所需的狀態位元。本設計輸入 A,BA,B 與結果 RR 皆為 WW 位元,支援 ADD、SUB、AND、OR、XOR。算術結果一律截為低 WW 位元。同一序列可解讀為 unsigned無符號(unsigned)將位元序列解讀為非負整數。n 位元範圍為 0 至 2^n−1;相同位元序列的帶符號解讀可能得到不同數值。 詳細內容 或二補數 signed,因此分開輸出 carry 與 overflow,不必依符號解讀建立兩個加法器。

旗標為 Z=(R=0)Z=(R=0)、N=RW−1N=R_{W-1}。Z 是選定結果整體的 reduction NOR,N 是最高位元。N=1 表示儲存位元序列的 signed 解讀為負;若發生 overflow,可能與無限精度真實總和的符號不同。

分開 carry 與 overflow

加法的 C 是擴展總和 TT 的最高位元。

T={0,A}+{0,B},R=T[W−1:0],C=T[W]T=\{0,A\}+\{0,B\},\qquad R=T[W-1:0],\quad C=T[W]

兩輸入同號而結果變號時,V=1。以 a,b,ra,b,r 分別表示最高位元,則:

Vadd=¬(a⊕b)∧(a⊕r)V_{\mathrm{add}}=\neg(a\oplus b)\land(a\oplus r)

8 位元 255+1255+1 得 R=0、C=1、V=0,signed 是 −1+1=0-1+1=0,沒有超出範圍。反之 127+1127+1 得 R=0x80、C=0、V=1;unsigned 128 可表示,卻超過 signed 最大值 127。若把 C、V 合併,就無法區分這兩種情況。

減法只反相反相是將 0 變為 1、1 變為 0 的 NOT 運算。公式上方的橫線表示對線下的整個運算式套用 NOT。 詳細內容 W 位元的 B,再補 0 擴展,即 T={0,A}+{0,¬B}+1T=\{0,A\}+\{0,\neg B\}+1。若反相整個 W+1 位元,最高 carry 的意義會改變。本課定義 C=1 為沒有借位,因此 unsigned A<BA<B 為 ¬C\neg C。

Vsub=(a⊕b)∧(a⊕r)V_{\mathrm{sub}}=(a\oplus b)\land(a\oplus r)

只有異號相減才可能 signed overflow。比較指令可只用 SUB 旗標而不儲存 R。Signed A<BA<B 為 N⊕VN\oplus V,signed A≤BA\le B 為 Z∨(N⊕V)Z\lor(N\oplus V)。例如 −128−1-128-1 儲存結果為 +127,但 V=1 可修正只看 N 的錯誤。

下方是 8 位元 ADD 範例:unsigned 結果可表示,signed 結果卻超出範圍。請確認同一總和可以同時 C=0、V=1。

以 127 + 1 區分 C 與 V
  1. A=7F · B=01: 帶符號:127 + 1
  2. 9 位元和 T: 0_10000000
  3. 8 位元結果 R: 80 → 帶符號 −128
  4. 狀態旗標: Z=0 · N=1 · C=0 · V=1

共用加法器與明確輸出規則

下方 RTL 假設 W≥2,opcode 0~4 為 ADD、SUB、AND、OR、XOR。邏輯運算設 C,V=0;未使用 opcode 設 R=0,因此 Z=1,其餘旗標為 0。這是此 ALU 的介面契約,不是模仿某個 CPU 指令集。

SystemVerilog
module alu #(parameter int W = 8) (
  input  logic [W-1:0] a, b,
  input  logic [2:0] op,
  output logic [W-1:0] y,
  output logic z, n, c, v
);
  logic sub;
  logic [W-1:0] bx;
  logic [W:0] sum;
  always_comb begin
    sub = (op == 3'd1);
    bx = b ^ {W{sub}};
    sum = {1'b0, a} + {1'b0, bx}
        + {{W{1'b0}}, sub};
    y = '0;
    c = 1'b0;
    v = 1'b0;
    case (op)
      3'd0, 3'd1: begin
        y = sum[W-1:0];
        c = sum[W];
        if (sub)
          v = (a[W-1] ^ b[W-1]) & (a[W-1] ^ y[W-1]);
        else
          v = ~(a[W-1] ^ b[W-1]) & (a[W-1] ^ y[W-1]);
      end
      3'd2: y = a & b;
      3'd3: y = a | b;
      3'd4: y = a ^ b;
      default: y = '0;
    endcase
    z = ~(|y);
    n = y[W-1];
  end
endmodule

條件式 B 反相與初始 carry,將 ADD/SUB 表達為同一加法結構。各分支先決定 y,再計算 Z,N,讓邏輯運算也有一致狀態。預設指定定義全部輸出路徑並避免鎖存器鎖存器在控制訊號啟用時跟隨輸入,未啟用時保持原值。它與只在邊緣儲存資料的正反器不同。 詳細內容。此處沒有暫存器暫存器儲存多個位元的狀態。本課程中的同步暫存器會在時脈邊緣儲存指定的輸入。 詳細內容,因此沒有以時脈週期計算的延遲,但仍有實際傳播延遲;連同運算選擇 MUX 與零偵測電路,都必須在下一暫存器 setup 期限內到達。

驗證時搭配 0、unsigned 最大值、signed 最大最小值與邊界兩側。分別比對 R 與 modulo 2W2^W 參考值、C 與 unsigned 擴展總和、V 與是否超出 signed 範圍的判定結果。R 正確不代表旗標定義也正確。

將結果符號、零、unsigned carry、signed overflow 分開的實際例子,可見 Arm 條件旗標說明。

自己試試看

8 位元 ALU 中,求 (1) 0x7F+0x01、(2) 0xFF+0x01、(3) 0x00−0x01、(4) 0x80−0x01 的 R,Z,N,C,V,並說明 (4) 的 signed 比較為何不能只用 N。

查看解說

依 (R,Z,N,C,V) 順序:(1) (0x80,0,1,0,1)、(2) (0x00,1,0,1,0)、(3) (0xFF,0,1,0,0)、(4) (0x7F,0,0,1,1)。(3) 發生 unsigned borrow,故 C=0,而 signed −1 可表示。(4) unsigned 128−1=127,無借位,C=1;signed 則為 −128−1=−129,超出範圍,V=1。儲存 R 的 N=0 無法反映真實差值的符號,但 signed A<B 的 N xor V=1 可正確判為真。

此選擇適用於本瀏覽器,隨時可從頁尾變更。