← 기술 지식

기술 지식 / 컴퓨터 과학 / 운영체제 / 프로세스·스레드

CPU 명령어 파이프라인과 해저드

명령어를 여러 단계로 겹쳐 실행할 때 데이터·제어·구조적 해저드가 stall, forwarding, flush로 어떻게 처리되는지 설명합니다.

시스템 · 원리·구현·운영

자료 대조일 · 적용 버전과 실행 여부는 본문의 검증 범위에 명시합니다.

기술 지식 트리

파이프라인의 핵심은 명령어 하나를 여러 조각으로 잘라 단일 명령어의 완료 시간을 자동으로 줄이는 데 있지 않습니다. 인출과 해석을 끝낸 명령어가 연산하는 동안 다음 명령어가 인출되도록 겹쳐서, 독립적인 명령어 흐름의 완료 간격을 줄이는 데 있습니다. 여기서는 IF, ID, EX, MEM, WB라는 다섯 단계의 교육용 in-order 모델을 사용합니다. 실제 프로세서는 단계 수, 실행 포트, 분기 해결 위치가 다르므로 아래 수치는 메커니즘을 추적하기 위한 계산입니다.

단계와 상태

각 pipeline register에는 적어도 valid, opcode, source/destination register, operand-ready 시점을 기록한다고 생각하면 설명이 명확해집니다. valid가 0이면 그 칸은 bubble이라 자원은 점유하지 않지만 파이프라인의 시간 슬롯은 지나갑니다. 독립 명령어 네 개를 1사이클 단계로 흘리면 첫 명령어는 1~5사이클을 거쳐 5사이클에 완료되고, 뒤 명령어는 6, 7, 8사이클에 완료됩니다. 단일 명령어의 지연시간은 5사이클이지만 steady state의 완료 간격은 1사이클입니다.

데이터 의존성과 시점

add r1,r2,r3가 사이클 3의 EX 끝에서 결과를 만들고 다음 sub r4,r1,r5가 사이클 4의 EX 입력에서 그 값을 요구한다고 하겠습니다. WB까지 기다리는 대신 EX/MEM pipeline register의 결과를 ALU 입력 mux로 우회하면 RAW 의존성을 한 사이클 지연 없이 처리할 수 있습니다. 반대로 load r1,0(r2)는 같은 모델에서 MEM 끝인 사이클 4에야 값이 생깁니다. 바로 뒤 add의 EX 요구 시점과 겹치므로 interlock이 ID를 멈추고 bubble 하나를 삽입한 뒤 사이클 5에 forwarding합니다. source와 destination 이름이 같다는 검사는 필요조건일 뿐, 결과 가용 시점과 consumer 요구 시점을 함께 비교해야 합니다.

구조적 자원

구조적 해저드는 값이 아니라 같은 사이클에 필요한 자원의 수가 부족해서 생깁니다. 단일 포트 메모리를 쓰는 모델에서 사이클 4에 한 명령어의 IF와 다른 명령어의 MEM이 동시에 오면 둘 중 하나를 사이클 5로 미뤄야 합니다. instruction/data cache를 분리하면 이 충돌을 없앨 수 있지만 포트와 태그 비교기가 늘어납니다. 실행 유닛을 복제해도 register-file read port와 writeback bus가 동시에 병목이 될 수 있으므로 한 유닛의 사용률만 보고 설계를 결정하면 안 됩니다. 자원별 점유표와 목표 initiation interval을 같이 계산해야 합니다.

제어 흐름

분기가 EX에서 resolve되는 5단계 모델에서 not-taken으로 예측했지만 실제로 taken이면, 분기 뒤에 순차 주소로 들어온 IF·ID의 두 명령어가 잘못된 경로입니다. PC만 target으로 바꾸는 것으로 충분하지 않습니다. 해당 pipeline register와 실행 대기열의 valid를 지우고, 잘못된 결과와 fault 후보가 retirement에 도달하지 못하게 한 뒤 target에서 다시 fetch해야 합니다. resolve가 MEM처럼 더 뒤로 이동하면 같은 fetch 폭에서 폐기할 명령어가 늘어 penalty도 커질 수 있습니다. 예측이 맞는 경우에는 이미 채운 경로를 그대로 사용하므로 flush가 발생하지 않습니다.

지연시간과 처리량

깊은 파이프라인은 조합 논리를 더 잘게 나눠 높은 클록을 노릴 수 있지만 fill·drain, 분기 회복, 의존성 chain 비용을 늘릴 수 있습니다. 예를 들어 5단계와 10단계가 모두 단계당 1사이클이라고 가정하면 단일 명령어는 각각 5와 10사이클입니다. 독립 명령어 네 개의 완료 시점은 5,6,7,8 대 10,11,12,13입니다. 긴 독립 stream에서는 두 모델 모두 이상적으로 한 사이클마다 완료하지만, r1을 만든 직후 계속 사용하는 chain은 각 producer latency에 묶입니다. 따라서 IPC 하나가 아니라 dependency stall, branch miss, cache miss를 분리해 봅니다.

구현 추적

교육용 시뮬레이터는 사이클 시작마다 WB, MEM, EX, ID, IF 순서로 자원과 valid를 갱신하고, forwarding 후보를 계산한 뒤 stall 또는 bubble을 넣는 방식이 안전합니다. add→sub, load→add, IF/MEM 단일 포트, taken branch 오예측을 별도 테스트로 두면 원인이 섞이지 않습니다. ALU 결과는 EX 끝, load 결과는 MEM 끝이라는 가정은 trace에 명시하고, 실제 대상 CPU의 latency로 바꾸려면 해당 ISA·마이크로아키텍처 자료나 counter를 추가해야 합니다.

해저드의 판정과 회복인출·발행: opcode·valid·PC. 값 시점: producer·consumer. 자원 점유: 포트·유닛. 분기 경로: 예측·target. forwarding: 우회 입력. stall·bubble: 늦은 값·자원. squash·refill: 오예측 회복. 순서 완료: 유효 결과만 반영source 확인요구 자원다음 PC값이 이미 준비값이 늦음동시 점유 충돌target 불일치의존 진행bubble 뒤 진행target 재인출인출·발행opcode·valid·PC값 시점producer·consumer자원 점유포트·유닛분기 경로예측·targetforwarding우회 입력stall·bubble늦은 값·자원squash·refill오예측 회복순서 완료유효 결과만 반영
해저드의 판정과 회복 값의 준비 시점, 자원 점유, 다음 PC를 각각 판정한 뒤 forwarding·stall·flush를 선택합니다.
그림을 글로 읽기
  • 인출·발행: opcode·valid·PC
  • 값 시점: producer·consumer
  • 자원 점유: 포트·유닛
  • 분기 경로: 예측·target
  • forwarding: 우회 입력
  • stall·bubble: 늦은 값·자원
  • squash·refill: 오예측 회복
  • 순서 완료: 유효 결과만 반영
  1. 인출·발행 → 값 시점: source 확인
  2. 인출·발행 → 자원 점유: 요구 자원
  3. 인출·발행 → 분기 경로: 다음 PC
  4. 값 시점 → forwarding: 값이 이미 준비
  5. 값 시점 → stall·bubble: 값이 늦음
  6. 자원 점유 → stall·bubble: 동시 점유 충돌
  7. 분기 경로 → squash·refill: target 불일치
  8. forwarding → 순서 완료: 의존 진행
  9. stall·bubble → 순서 완료: bubble 뒤 진행
  10. squash·refill → 순서 완료: target 재인출

실패와 비용

forwarding 경로는 mux, 배선, timing 검증 비용을 만들고, 포트 복제는 면적·전력을 소비합니다. 모든 RAW를 없앤다고 가정하면 load miss와 긴 실행 latency를 설명하지 못하고, 실행 유닛을 늘리면 모든 구조적 병목이 사라진다고 보면 register-file과 writeback 병목을 놓칩니다. flush가 cache 흔적까지 지운다고 말하는 것도 correctness와 microarchitecture 관찰을 섞는 오류입니다.

참고 자료와 한계

후속·관련 개념

함께 읽을 문서

분야별 학습 경로

전체 기술 지식