PipeScope
속이 들여다보이는 5단계 파이프라인 CPU입니다. GCC로 빌드한 RISC-V와 MIPS 프로그램을 브라우저에서 한 사이클씩 실행하면서 포워딩과 스톨, 분기 뒤의 flush, 메모리 접근, 주변 장치 입출력이 일어나는 모습을 볼 수 있습니다.
1981년, 스탠퍼드 대학의 존 헤네시와 대학원생들이 새 프로세서를 설계하기 시작했습니다. 이름은 MIPS, ’Microprocessor without Interlocked Pipeline Stages’의 머리글자였습니다. 파이프라인에서 뒤 명령어가 앞 명령어의 결과를 너무 일찍 쓰려 하면, 보통은 인터록이라는 하드웨어 회로가 뒤 명령어를 멈춰 세웁니다. 헤네시의 팀은 이 회로를 뺐습니다. 문제가 되는 순서는 컴파일러가 명령어 순서를 바꿔 피했고, 분기 바로 뒤의 한 칸(지연 슬롯)을 채우는 일도 컴파일러가 맡았습니다.
프로젝트는 1984년에 끝났고, 이듬해 상용 칩 R2000이 나왔습니다. 헤네시가 데이비드 패터슨과 함께 쓴 교재 『컴퓨터 구조 및 설계(Computer Organization and Design)』는 MIPS를 예로 들어 5단계 파이프라인을 설명했고, 2017년에는 RISC-V판이 나왔습니다. 같은 해 두 사람은 튜링상을 받았습니다. 2021년, MIPS 테크놀로지스는 MIPS 아키텍처 개발을 멈추고 RISC-V로 옮겨 갔습니다.
그 교재에서 파이프라인은 그림 한 장으로 나옵니다. 그런데 그림은 움직이지 않습니다. 명령어 다섯 개가 한꺼번에 흘러가는 동안 포워딩 경로는 언제 켜질까요? 로드 바로 뒤의 명령어는 왜 한 사이클을 쉬어야 할까요? 분기가 성립하면 그사이 미리 읽어 온 명령어는 어떻게 될까요? PipeScope는 교재에 실린 바로 그 데이터패스 위로 실제 프로그램을 한 사이클씩 흘려보내면서 이 질문들에 답합니다. RISC-V와 MIPS를 모두 실행하므로, 헤네시의 팀이 컴파일러에 맡겼던 지연 슬롯과 RISC-V의 flush를 나란히 비교할 수 있습니다.
화면 속 파이프라인은 실제로 프로그램을 실행합니다. Rust로 작성해 WebAssembly로 컴파일한 파이프라인 시뮬레이터가 GCC로 빌드한 ELF 실행 파일을 그대로 읽어서 실행합니다. RISC-V(RV32IM)와 MIPS32를 모두 지원하고, 실행 파일을 열면 어느 구조인지 알아본 뒤 데이터패스 그림과 레지스터 이름, 명령어 설명을 그 구조에 맞게 바꿉니다. 실행 파일 안에 C 소스가 함께 들어 있어서, 지금 각 단계에 있는 명령어가 소스의 어느 줄에서 나왔는지도 따라갈 수 있습니다. 실행 결과는 같은 프로그램을 명령어 하나씩 실행하는 기준 시뮬레이터와 비교해 검증합니다.

무엇을 볼 수 있나요
- 데이터패스. 컴퓨터 구조 교재에 나오는 5단계 데이터패스를 제어 유닛, 해저드 검출 유닛, 포워딩 유닛까지 빠짐없이 그렸습니다. RISC-V는 블록 31개와 신호 81개, MIPS는 블록 34개와 신호 83개입니다. 이번 사이클에 실제로 쓰인 경로에만 색이 들어오고, 확대하면 선의 이름과 비트 폭이, 더 확대하면 선마다 흐르는 값이 나타납니다.
- 이번 사이클에 일어난 일. 단계마다 무슨 일이 있었는지 문장으로 풀어 줍니다. 해저드가 왜 생겼고 어떻게 해결됐는지, 포워딩된 값이 어디서 와서 어디로 들어갔는지, 분기 때문에 어떤 명령어가 버려졌는지를 그 자리에서 읽을 수 있습니다.
- 인스펙터. 블록을 누르면 그 블록의 입력과 출력, 이번 사이클에 한 일이 나옵니다. 선을 누르면 값을 16진수, 10진수, 2진수로 보여 주고, 제어 신호라면 값마다 무슨 뜻인지도 표로 보여 줍니다.
- 시스템 버스와 7-세그먼트. CPU 칩 바깥에서 본 그림입니다. RAM에서 명령어 4바이트를 읽어 조립하는 과정, 주소 디코더가 RAM과 주변 장치 가운데 하나를 고르는 과정,
sw한 번이 8자리 7-세그먼트의 숫자를 바꾸는 과정을 바이트 단위로 따라갑니다. - 되감기와 비교. 최근 20,000사이클까지 거꾸로 돌릴 수 있습니다. 포워딩을 끄고 스톨만으로 실행해 보면 결과는 같은데 CPI가 얼마나 나빠지는지 바로 확인할 수 있습니다. 해저드 처리를 아예 꺼서 프로그램이 틀린 답을 내는 모습도 볼 수 있습니다.


RISC-V
RISC-V의 32비트 정수 명령어(RV32I)와 곱셈·나눗셈 확장(M)을 구현했습니다. 즉시값 생성기가 명령어 형식(I·S·B·U·J)에 따라 흩어진 즉시값 비트를 모으고, 분기와 jal은 명령어 자신의 PC를 밑으로 목표 주소를 계산합니다. 분기는 ID 단계에서 결정합니다. RISC-V에는 지연 슬롯이 없으므로, 분기가 성립하면 IF가 그사이 읽어 온 명령어 하나를 버립니다. 이 flush는 IF 단계 머리글과 파이프라인 차트의 지워진 칸, 데이터패스의 IF.Flush 선으로 보이고, 툴바가 그 횟수를 셉니다. 압축 명령어(C 확장), ecall, CSR 명령어는 지원하지 않습니다.
MIPS
같은 파이프라인에서 MIPS32도 실행합니다. GCC가 내는 정수 명령어를 구현했고, 분기 뒤의 지연 슬롯도 실제 MIPS처럼 동작하므로 GCC가 만든 코드를 고치지 않고 그대로 실행합니다. 곱셈과 나눗셈의 결과는 HI/LO 레지스터에 들어가고, 조건부 이동과 트랩도 지원합니다. 예제는 같은 C 소스를 두 구조로 빌드해 두었습니다. 예제를 바꿔 가며 분기 뒤의 flush와 지연 슬롯을 나란히 비교하고, 같은 나눗셈이 RISC-V에서는 divu로 남고 MIPS에서는 곱셈(mult)으로 바뀌는 모습도 볼 수 있습니다.

지원하지 않는 것
두 구조 모두 부동소수점, 시스템 콜, 인터럽트, 캐시는 없습니다. 운영체제가 없으니 printf도 없고, 출력은 메모리에 매핑된 7-세그먼트로 합니다.
시작하기
여기서 앱을 열면 RISC-V 해저드 예제가 실려 있습니다. 다음(→)을 누를 때마다 한 사이클씩 진행하고, 이전(←)을 누르면 되돌아갑니다. 예제 목록은 RISC-V와 MIPS 두 묶음으로 나뉘어 있고, 묶음마다 해저드 예제와 C 프로그램을 빌드한 예제 여섯 개가 있습니다. 화면은 한국어, 영어, 일본어로 볼 수 있고 실행하는 도중에도 바꿀 수 있습니다.