Altifigence Academy

51 / 63 · 개념

ALU와 zero·negative·carry·overflow 플래그

공유 가산기로 ADD/SUB를 구성하고 carry와 signed overflow를 분리해 비교 조건까지 유도합니다.

선수 지식: 2의 보수2의 보수 고정 폭 비트열로 부호 있는 정수를 나타내는 방식입니다. n비트 범위는 −2^(n−1)부터 2^(n−1)−1까지입니다. 자세히 보기, 가산기, 조합논리 MUX멀티플렉서 선택 신호에 따라 여러 입력 중 하나를 출력으로 연결하는 조합회로입니다. 선택 비트와 입력 번호의 대응을 명세해야 합니다. 자세히 보기, 비트폭 확장을 이해해야 합니다.

결과와 상태를 함께 만드는 ALU

ALU는 연산별 회로의 결과를 선택하고, 그 결과를 해석하는 데 필요한 상태 비트를 출력합니다. 이번 설계의 입력 A,BA,B와 결과 RR은 WW비트이며 ADD, SUB, AND, OR, XOR를 지원합니다. 산술 결과에서는 항상 하위 WW비트만 남깁니다. 같은 비트열을 unsignedunsigned 비트열을 음수가 없는 정수로 해석하는 규칙입니다. n비트의 범위는 0부터 2^n−1이며, 같은 비트열의 signed 해석과 다를 수 있습니다. 자세히 보기 또는 2의 보수 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를 분리하기

덧셈에서는 확장된 합 TT의 최상위 비트가 C입니다.

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입니다. 합 128은 unsigned로 표현할 수 있지만 signed 최댓값 127을 넘습니다. C와 V를 하나로 묶으면 이 두 경우를 구분할 수 없습니다.

뺄셈에서는 W비트 B만 반전부정 0을 1로, 1을 0으로 바꾸는 NOT 연산입니다. 수식 위의 선은 선 아래 식 전체에 NOT을 적용한다는 뜻입니다. 자세히 보기한 뒤, 상위에 0을 붙여 확장합니다. 즉 T={0,A}+{0,¬B}+1T=\{0,A\}+\{0,\neg B\}+1입니다. W+1비트 전체를 반전하면 상위 carry의 뜻이 달라집니다. 이 강의는 C=1을 borrow 없음으로 정의합니다. 따라서 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: signed 127 + 1
  2. 9비트 합 T: 0_10000000
  3. 8비트 결과 R: 80 → signed −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입니다. 이는 특정 CPU 명령어 집합을 따르는 규칙이 아니라, 이 ALU에서 정한 출력 규칙입니다.

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을 계산하므로 논리 연산의 결과도 같은 규칙으로 Z와 N에 반영됩니다. 기본값을 대입해 모든 조건에서 출력이 정해지도록 하므로 래치래치 제어 신호가 활성인 동안 입력을 따라가고 비활성일 때 값을 유지하는 저장소자입니다. 에지에서만 저장하는 플립플롭과 다릅니다. 자세히 보기가 생기지 않습니다. 여기에는 레지스터레지스터 여러 비트의 상태를 저장하는 회로입니다. 이 과정의 동기식 레지스터는 클록 에지에서 정해진 입력을 저장합니다. 자세히 보기가 없어 클록 단위의 계산 지연은 없지만, 실제 신호 전파 지연은 있습니다. 연산 선택 MUX와 zero 검출 회로를 거친 신호도 다음 레지스터의 setup 시간 안에 도착해야 합니다.

검증에서는 0, unsigned 최댓값, signed 최댓값·최솟값과 경계 바로 안팎의 값을 조합해 검사하세요. R은 2W2^W로 나눈 나머지와, C는 unsigned로 확장한 합의 carry와, V는 signed 표현 범위를 넘는지와 각각 비교해야 합니다. R이 맞아도 플래그 정의가 틀릴 수 있습니다.

플래그로 결과의 부호·0 여부·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이므로 borrow가 없어 C=1입니다. signed로는 −128−1=−129가 범위를 벗어나 V=1이고, 저장된 R의 N=0은 실제 차의 부호를 반영하지 못합니다. signed A<B는 N xor V=1이므로 올바르게 참을 얻습니다.

선택은 이 브라우저에만 적용됩니다. 언제든 푸터에서 변경할 수 있습니다.