1. 파이프라이닝 개요: 겹쳐서 처리해 처리량(throughput) 올리기
1.1. 파이프라인의 핵심
- 여러 명령어를 서로 다른 단계에서 동시에 실행
- 처리량 증가가 목적(=더 많은 instruction/sec)
- 단, 개별 명령어의 latency 자체가 줄어드는 건 아님
1.2. RISC-V 5단계 파이프라인
- IF: instruction fetch
- ID: decode + register read
- EX: execute / address calc
- MEM: data memory access
- WB: write back
1.3. 파이프라인 성능 감각(균형의 중요성)
- 이상적으로 각 stage 시간이 같으면 속도향상 ≈ stage 수
- stage가 불균형이면 speedup 감소
1.4. ISA와 파이프라인의 궁합
- RISC-V: 고정 길이 32-bit, 규칙적인 포맷 → fetch/decode 단순
- load/store 구조 → 주소계산(EX)과 메모리접근(MEM) 분리 쉬움
2. 파이프라인 해저드(Hazards)
2.1 해저드 3종
- Structural hazard: 자원 충돌(예: 단일 메모리라면 IF와 MEM이 충돌)
- Data hazard: 이전 명령어 결과가 아직 준비 안 됨
- Control hazard: 분기/예외 등으로 다음 PC가 불확실
3. Data Hazard 해결: Forwarding(=Bypassing)과 Stalling
3.1. Forwarding의 아이디어
- 결과를 레지스터에 쓰기(WB)까지 기다리지 말고,
- 계산된 즉시(EX/MEM, MEM/WB) 필요한 곳으로 우회 전달
3.2. Forwarding이 필요한지 “검출”하는 법
- 파이프라인 레지스터에 레지스터 번호를 함께 넘긴다.
- EX 단계의 소스 레지스터:
ID/EX.Rs1,ID/EX.Rs2
- EX 단계의 소스 레지스터:
- 잠재적 제공자(앞선 명령어의 목적지)
EX/MEM.Rd,MEM/WB.Rd
- Forward 조건의 기본형(개념)
EX/MEM.Rd == ID/EX.Rs1또는== Rs2MEM/WB.Rd == ID/EX.Rs1또는== Rs2
- 단,
- 해당 명령이 RegWrite=1이어야 하고
- Rd가 x0(0번 레지스터)면 제외
3.3. Double data hazard(가장 최신 값 우선)
- EX/MEM과 MEM/WB 둘 다 매칭되면 더 최신인 EX/MEM 값을 선택
- 따라서 MEM/WB 조건에 “EX/MEM 조건이 성립하지 않을 때만” 같은 배제 조건을 추가
3.4. Load-use hazard: Forwarding만으로 해결 불가
- lw는 데이터가 MEM 단계 끝에서야 나오므로,
- 바로 다음 명령이 그 값을 EX에서 필요로 하면 시간상 전달 불가
- 해결: 1-cycle stall + bubble 삽입
3.5. Stall 구현(하드웨어 동작 관점)
- ID/EX의 control 신호를 0으로 만들어 NOP처럼 만들기
- PC와 IF/ID 레지스터 업데이트를 막아 동일 명령을 다시 decode
- 1사이클 쉬면 lw의 데이터가 준비되어 이후 forward 가능
4. Control Hazard: 분기(Branch) 처리
4.1. 기본 문제
- 분기 결과가 확정되기 전에는 다음에 fetch할 명령이 불확실
- 단순하게는 분기 확정까지 stall(branch penalty 큼)
4.2. 지연 줄이기: 더 이른 단계에서 분기 결정
- ID 단계에서
- 타깃 주소 adder
- 레지스터 comparator 를 추가하여 분기 결정을 앞당김
4.3. Branch prediction(예측)
-
파이프라인이 깊어질수록 stall 비용이 커져 예측이 필요
-
단순 정적 예측 예
- forward branch는 not taken
- backward branch(루프)는 taken
4.4. 동적 분기 예측(BHT/Branch History Table)
- 분기 PC로 테이블 인덱싱 → taken/not taken 기록
- 예측이 틀리면 flush하고 기록 갱신
- 1-bit predictor 단점: 루프 끝에서 2번 틀릴 수 있음 → 2-bit predictor(포화 카운터)로 완화
- 타깃 주소 계산도 비용이므로 BTB(Branch Target Buffer)로 타깃 캐싱
5. 예외/인터럽트(Exceptions & Interrupts)
5.1. 용어 정리
- Exception: CPU 내부에서 발생(불법 opcode, syscall 등)
- Interrupt: 외부 I/O에서 발생
5.2. RISC-V 예외 처리 기본 메커니즘
- 문제 명령어의 PC 저장: SEPC
- 원인 저장: SCAUSE
- 핸들러 주소로 점프(예: 0x1C090000 가정)
5.3. 파이프라인에서 예외 = 또 하나의 control hazard
- 예외 난 명령이 레지스터/메모리를 오염시키면 안 됨
- 이전 명령은 완료시키고,
- 예외 명령 및 이후 명령은 flush
- 분기 mispredict flush와 유사한 하드웨어 재사용 가능
5.4. Precise vs. Imprecise exceptions
- 단순 파이프라인: 가장 앞선(earliest) 예외만 처리하며 이후 flush → precise 유지 가능
- 다중발행/Out-of-order는 precise 유지가 어려워짐
6. ILP(Instruction-Level Parallelism): 더 멀리 가면?
6.1. ILP 확장 방법
- 더 깊은 파이프라인: stage를 쪼개 클록 단축
- Multiple issue: 한 사이클에 여러 명령 발행(IPC>1)
6.2. Multiple issue의 두 방식
- Static multiple issue(VLIW 스타일): 컴파일러가 패킷(issue packet)을 구성, hazard 회피
- Dynamic multiple issue(슈퍼스칼라): CPU가 런타임에 발행 선택, hazard를 하드웨어가 해결
6.3. Speculation(추측 실행)
-
분기 결과/로드 값을 추측하고 먼저 실행
-
맞으면 commit, 틀리면 rollback(버퍼 flush)
-
추측 실행 중 예외가 나면?
- 정적 추측: ISA 지원으로 예외를 지연(defer)
- 동적 추측: 예외도 버퍼에 보관했다가 commit 시점에 확정
7. Static Dual-Issue RISC-V 예시
7.1. 패킷 제약
-
2-issue 패킷
- 슬롯1: ALU/branch
- 슬롯2: load/store
-
64-bit 정렬, 필요 시 nop 패딩
7.2. 새로 생기는 해저드 감각
- 같은 패킷에서 ALU 결과를 곧바로 load/store 주소로 쓰기 어려움
- 예:
add x10,...와lw x2,0(x10)는 패킷 분리 필요(사실상 stall)
- 예:
7.3. 스케줄링/루프 언롤링
- 컴파일러가 더 공격적으로 재배치해야 IPC가 올라감
- Loop unrolling로 병렬성 노출 + 루프 오버헤드 감소
- 레지스터를 복제해서 쓰는 register renaming(이름 의존성 제거)
8. Dynamic Scheduling(Out-of-order) 개요
8.1. 왜 하드웨어가 스케줄링하나?
- 컴파일러가 예측 불가한 stall 존재(캐시 miss 등)
- 분기 결과는 런타임에 결정
- ISA는 같아도 구현마다 latency/hazard가 다름
8.2. 구조(개념도)
- in-order issue(의존성 보존) + out-of-order execute(대기 줄이기) + in-order commit(정확한 상태 유지)
- reservation station, reorder buffer가 사실상 레지스터 리네이밍 제공
9. 전력/현실: 더 복잡하면 더 많이 먹는다
- 동적 스케줄링 + speculation은 성능을 올리지만 전력 비용이 큼
- 그래서 “여러 개의 단순 코어”가 더 나을 수 있다는 관점 등장
- 강의자료는 ARM Cortex-A53 vs Intel Core i7 비교(시장, TDP, 파이프라인, issue width, branch prediction, 캐시 구조 등)를 통해 설계 트레이드오프를 보여줌
10. ILP 사례: Matrix Multiply 최적화 감각
- 루프 언롤링 + SIMD(AVX 등)로 IPC/처리량 개선
- unoptimized → AVX → AVX+unroll로 성능이 크게 향상되는 예시
11. 마무리: 흔한 오해/주의점 & 결론
11.1. Fallacies / Pitfalls
- 파이프라이닝은 쉽다. → 아이디어는 쉽지만 해저드 검출/처리 디테일이 악마
- 기술과 무관하다. → 트랜지스터 여유가 있어야 복잡한 기법이 가능
- ISA가 복잡하면 파이프라이닝 오버헤드가 커짐(복잡 주소지정, side-effect 등)
11.2. 결론 요약
-
ISA ↔ datapath/control은 서로 영향을 주고받는다
-
파이프라이닝은 throughput을 올리지만 latency는 그대로
-
hazard(구조/데이터/제어)가 핵심 난제
-
multiple issue, OoO, speculation으로 ILP를 더 끌어올리려 하지만
- 실제 의존성과 전력 한계(power wall)가 발목을 잡는다.