---
title: "retirement trace: 계산된 9와 확정된 3을 구별하는 기록"
author: "브레이브브라우저쓰자"
published_at: "2026-10-16T05:53:02.160Z"
updated_at: "2026-10-06T00:43:37.485Z"
tags: ["retirement trace"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/retirement-trace-%EA%B3%84%EC%82%B0%EB%90%9C-9%EC%99%80-%ED%99%95%EC%A0%95%EB%90%9C-3%EC%9D%84-%EA%B5%AC%EB%B3%84%ED%95%98%EB%8A%94-%EA%B8%B0%EB%A1%9D"
ai_assisted: true
---

# retirement trace: 계산된 9와 확정된 3을 구별하는 기록

이 글은 AI가 활용됐습니다.

[원문](https://ariser.io/@writer_a9817d5a8de0/retirement-trace-%EA%B3%84%EC%82%B0%EB%90%9C-9%EC%99%80-%ED%99%95%EC%A0%95%EB%90%9C-3%EC%9D%84-%EA%B5%AC%EB%B3%84%ED%95%98%EB%8A%94-%EA%B8%B0%EB%A1%9D)

프로세서 내부에서 x5에 쓸 9가 계산되었는데, 실행이 끝난 프로그램의 x5에는 3이 남았다. 이것만으로 9가 잘못된 계산이었다고 판단할 수 있을까. 예측한 경로에서 실행한 명령이 취소되었다면 내부 결과 9는 정상적인 추측 실행의 흔적일 수 있다. retirement trace는 이 내부 활동과 프로그램이 실제로 수행한 동작을 구분해 보는 관측 방법이다.

## 잘못된 경로의 완료는 실행 기록과 다르다

주소 0x100의 분기 B는 실제로 0x200으로 이동하지만, 처음에는 다음 주소 0x104로 진행한다고 예측했다고 하자. 잘못된 경로의 명령 A는 x5=9를 계산하고, 올바른 경로의 명령 C는 0x200에서 x5=3을 만든다. 모두 4바이트 명령이라는 가상 예다.

내부 writeback만 모으면 A의 9가 기록될 수 있다. 그러나 확정된 명령만 관측하는 방식에서는 다음이 핵심 기록이 된다. 명령의 전체 인코딩이나 입력 필드는 생략했다.

| 순서 | 명령 주소 | 다음 주소 | 정상 레지스터 변경 |
|---|---|---|---|
| 0 | 0x100 | 0x200 | 없음 |
| 1 | 0x200 | 0x204 | x5=3 |

취소된 A는 이 확정 스트림에 들어오지 않는다. 내부에서 계산했다는 이유로 A의 9를 프로그램의 동작으로 비교하면 정상적인 추측 실행을 오류로 판정한다. 반대로 A의 변경을 정말 architectural state에 노출했다면, 뒤에 C가 3으로 덮었더라도 중간의 잘못된 경계가 사라지는 것은 아니다.

BOOM은 실행 완료와 ROB의 순서 있는 commit을 구별하며, 잘못 예측한 경로의 명령을 취소하는 절차를 설명한다. retirement 관측은 이런 설계가 프로그램에 보이는 동작을 제대로 지켰는지 확인하는 데 유용하다. [BOOM, The Commit Stage](https://docs.boom-core.org/en/latest/sections/reorder-buffer.html#the-commit-stage)

## RVFI는 주소만 나열하는 인터페이스가 아니다

RISC-V Formal의 RVFI는 한 사이클에 관측할 수 있는 최대 명령 수 NRET에 맞춰 여러 채널을 제공한다. rvfi_valid가 켜진 채널에서만 그 명령의 필드가 유효하다. rvfi_order는 중복과 빠진 번호 없이 명령의 순서를 식별한다. PC 전후, 읽은 논리 레지스터의 값, 쓴 목적지와 값, 메모리 접근의 주소·바이트 마스크 등도 함께 보고한다. [YosysHQ, RVFI specification](https://github.com/YosysHQ/riscv-formal/blob/main/docs/source/rvfi.rst)

이 정보가 있어야 “명령 주소가 맞았다”를 넘어 계산의 상태 변화를 확인할 수 있다. 예를 들어 ADDI가 x5의 이전 값에 1을 더하는 명령이라면, 보고한 입력값과 목적지 값이 그 관계를 만족하는지 확인할 수 있다. 입력 번호만 맞고 이미 바뀐 다른 버전의 값을 사용한 오류도 이런 비교에서 드러난다.

인터페이스의 세부 규칙도 관측의 일부다. 목적지 변경이 없는 명령에서는 rvfi_rd_addr가 0이고 rvfi_rd_wdata도 0이어야 한다. valid가 꺼진 채널의 임의 비트를 명령으로 해석하면 안 된다. RVFI 원문은 압축 명령에 원래의 압축 인코딩을 출력하는 규칙까지 정의한다. 소비자가 임의로 추정한 실행 정보보다, 명시된 필드의 의미를 따라야 한다.

## 출력된 순서와 취소 여부도 계약을 읽어야 한다

앞의 표는 rollback 확장을 사용하지 않고 확정된 명령만 보고하는 관측 방식을 가정했다. RVFI 전체 사양을 그런 방식 하나로 제한해서 읽으면 안 된다. 사양은 인과관계를 유지하는 재정렬된 retirement를 허용하며, 읽기가 의존하는 쓰기는 먼저 보고되어야 한다는 조건을 둔다. 출력된 클록 순서와 명령의 순서 번호를 같은 것으로 단정하지 않는 이유다.

또 RISCV_FORMAL_ROLLBACK을 사용하는 확장에서는 추측 명령을 보고하고 나중에 무효화할 수 있다. rollback 사건은 지정된 order 이상에 속한 이전 사이클의 패킷들을 무효로 만든다. 같은 사이클의 새 패킷은 다시 시작한 스트림에 속한다는 규칙도 있다. 이 모드에서 취소되기 전 패킷을 영구적인 정상 실행 기록으로 남기면 비교 결과가 잘못된다. [RVFI, Handling of speculative execution](https://github.com/YosysHQ/riscv-formal/blob/main/docs/source/rvfi.rst)

따라서 retirement trace라는 이름만 보고 “여기에는 반드시 이미 확정된 명령만 있다”고 가정하지 않는다. 사용하는 인터페이스가 확정 스트림인지, 취소를 포함하는 스트림인지 먼저 정하고 그 규칙대로 상태를 재구성해야 한다.

## 마지막 값만 비교하면 놓치는 오류

가상의 정상 명령 두 개가 x5=1, x5=2를 순서대로 만든다고 하자. 구현 오류로 첫 명령이 99를 만들고 둘째가 2를 만들면 마지막 x5만 비교한 검사는 통과할 수 있다. 명령마다 목적지 변경을 비교하면 첫 기록에서 바로 차이가 드러난다. 최종 덮어쓰기와 무관하게, 각 경계의 상태가 명령 의미와 맞았는지 보게 되는 것이다.

다만 trace를 달았다는 사실만으로 모든 조건을 검증한 것은 아니다. 보고 필드 자체가 잘못된 경로에서 만들어졌다면 관측의 신뢰성을 확인해야 한다. 메모리 바이트 마스크, 예외와 특권 상태, 외부 버스에서 발생한 접근은 적용한 인터페이스와 검사 범위에 맞춰 다뤄야 한다. RVFI 문서도 메모리·CSR와 외부 메모리 버스의 일관성 검사를 각각 설명한다. 몇 개의 레지스터 기록이 맞았다는 결과를 전체 코어의 정확성으로 확대할 수 없다.

retirement trace가 답하는 질문은 내부에서 얼마나 많은 연산이 일어났느냐보다, 어떤 명령의 어떤 변화가 프로그램의 동작으로 인정되었느냐다. 9를 만들었다가 취소된 A와 실제로 3을 확정한 C를 구별하고, 각 유효한 상태 변화를 명령 의미와 비교하면 빠른 추측 실행과 정확한 결과를 같은 관측 기준으로 검토할 수 있다.

