Altifigence Academy

51 / 63 · Konzept

ALU und Zero-, Negative-, Carry- und Overflow-Flags

ADD/SUB mit gemeinsamem Addierer implementieren und aus getrenntem Carry/Overflow Vergleichsbedingungen ableiten.

Voraussetzungen: ZweierkomplementZweierkomplement Darstellung vorzeichenbehafteter Ganzzahlen mit fester Bitbreite. n Bit reichen von −2^(n−1) bis 2^(n−1)−1. Mehr erfahren, Addierer, kombinatorischer MUXMultiplexer Kombinatorische Schaltung, die gemäß Auswahlsignal einen Eingang zum Ausgang verbindet. Die Zuordnung von Auswahlbits und Eingangsnummern muss festgelegt sein. Mehr erfahren und Bitbreitenerweiterung.

Eine ALU erzeugt Ergebnis und Status

Die ALU wählt zwischen Rechenergebnissen und liefert Statusbits zu deren Interpretation. Eingänge A,BA,B und Ergebnis RR haben WW Bit; unterstützt werden ADD, SUB, AND, OR und XOR. Arithmetik behält stets nur die unteren WW Bit. Da dieselben Bits unsignedUnsigned Interpretation einer Bitfolge als nichtnegative Ganzzahl. Der n-Bit-Bereich ist 0 bis 2^n−1 und kann sich von der signed-Interpretation derselben Bits unterscheiden. Mehr erfahren oder signed im Zweierkomplement gelesen werden können, werden Carry und Overflow getrennt ausgegeben. Dafür sind keine zwei verschiedenen Addierer nötig.

Die Flags sind Z=(R=0)Z=(R=0) und N=RW−1N=R_{W-1}. Z ist das Reduktions-NOR des gewählten Ergebnisses, N dessen höchstes Bit. N=1 bedeutet ein negatives gespeichertes signed-Ergebnis. Bei Overflow kann dessen Vorzeichen vom mathematischen Ergebnis mit unbegrenzter Genauigkeit abweichen.

Carry und Overflow trennen

Bei Addition ist C das oberste Bit der erweiterten Summe 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 ist 1, wenn die Eingänge gleiche Vorzeichen haben, das Ergebnis aber ein anderes. Für die höchsten Bits a,b,ra,b,r gilt:

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

In acht Bit ergibt 255+1255+1 R=0, C=1, V=0: Signed ist −1+1=0-1+1=0 darstellbar. Dagegen ergibt 127+1127+1 R=0x80, C=0, V=1: Unsigned passt 128, signed wird das Maximum 127 überschritten. Ein gemeinsames C/V-Flag könnte beide Fälle nicht unterscheiden.

Für Subtraktion wird nur das W-Bit-B invertiertInversion NOT vertauscht 0 und 1. Ein Überstrich wendet NOT auf den gesamten darunterstehenden Ausdruck an. Mehr erfahren und danach mit 0 erweitert: T={0,A}+{0,¬B}+1T=\{0,A\}+\{0,\neg B\}+1. Inversion aller W+1 Bit verändert die Carry-Bedeutung. Hier heißt C=1 kein Borrow; unsigned A<BA<B entspricht deshalb ¬C\neg C.

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

Signed-Overflow bei Subtraktion ist nur für verschiedene Eingangszeichen möglich. Ein Vergleich kann SUB-Flags nutzen, ohne R zu speichern. Signed A<BA<B ist N⊕VN\oplus V, A≤BA\le B ist Z∨(N⊕V)Z\lor(N\oplus V). Bei −128−1-128-1 wird etwa +127 gespeichert; V=1 korrigiert die irreführende alleinige Betrachtung von N.

Das 8-Bit-ADD-Beispiel unten passt unsigned, überschreitet aber signed den Bereich. C=0 und V=1 können bei derselben Summe gleichzeitig gelten.

Bei 127 + 1 zwischen C und V unterscheiden
  1. A=7F · B=01: signed 127 + 1
  2. 9-Bit-Summe T: 0_10000000
  3. 8-Bit-Ergebnis R: 80 → signed −128
  4. Statusflags: Z=0 · N=1 · C=0 · V=1

Gemeinsamer Addierer, explizite Ausgaberegeln

Das RTL setzt W≥2 voraus. Opcodes 0–4 sind ADD, SUB, AND, OR, XOR. Logikoperationen setzen C, V auf 0. Unbenutzte Opcodes liefern R=0, Z=1 und sonst 0. Dies ist der Vertrag dieser ALU, keine Nachbildung eines bestimmten CPU-Befehlssatzes.

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

Bedingte B-Inversion und Anfangsübertrag teilen eine Addierstruktur für ADD/SUB. y wird vor Z, N bestimmt, sodass auch Logikoperationen konsistente Flags erhalten. Standardzuweisungen definieren alle Pfade und verhindern LatchesLatch Speicherelement, das bei aktiver Steuerung dem Eingang folgt und sonst hält. Anders als ein Flipflop speichert es nicht nur an Flanken. Mehr erfahren. Ohne RegisterRegister Speichert einen Zustand aus mehreren Bits. Die synchronen Register dieses Kurses übernehmen festgelegte Eingaben an Taktflanken. Mehr erfahren gibt es keine Zykluslatenz, jedoch reale Laufzeit. Auch Operations-MUX und Nullerkennung müssen vor dem Setup des nächsten Registers fertig sein.

Testen Sie Paarungen von 0, unsigned-Maximum, signed-Minimum/-Maximum und benachbarten Grenzwerten. Prüfen Sie R anhand des Ergebnisses modulo 2W2^W, C anhand der erweiterten unsigned-Summe und V anhand der signed-Bereichsüberschreitung jeweils unabhängig. Ein korrektes R garantiert keine korrekten Flags.

Ein reales Beispiel der Trennung von Vorzeichen, Null, unsigned-Carry und signed-Overflow bietet Arms Erklärung der Bedingungsflags.

Selbst ausprobieren

Bestimmen Sie für acht Bit (R, Z, N, C, V) von (1) 0x7F+0x01, (2) 0xFF+0x01, (3) 0x00−0x01, (4) 0x80−0x01. Warum ist bei signed-Vergleich von (4) N allein falsch?

Erklärung lesen

(1) (0x80,0,1,0,1), (2) (0x00,1,0,1,0), (3) (0xFF,0,1,0,0), (4) (0x7F,0,0,1,1). In (3) gibt es unsigned Borrow, also C=0; signed −1 passt. In (4) ist unsigned 128−1=127 ohne Borrow, also C=1. Signed −128−1=−129 überschreitet den Bereich: V=1, während das gespeicherte N=0 nicht das echte Vorzeichen zeigt. N xor V=1 ergibt korrekt signed A<B.

Deine Auswahl gilt für diesen Browser. Du kannst sie jederzeit in der Fußzeile ändern.