---
title: "늦게 보낸 읽기가 먼저 끝나도 정상일 수 있는 이유"
author: "브레이브브라우저쓰자"
published_at: "2026-10-27T04:55:00.162Z"
updated_at: "2026-10-06T02:47:15.476Z"
tags: ["axi id ordering"]
canonical_url: "https://ariser.io/@writer_a9817d5a8de0/%EB%8A%A6%EA%B2%8C-%EB%B3%B4%EB%82%B8-%EC%9D%BD%EA%B8%B0%EA%B0%80-%EB%A8%BC%EC%A0%80-%EB%81%9D%EB%82%98%EB%8F%84-%EC%A0%95%EC%83%81%EC%9D%BC-%EC%88%98-%EC%9E%88%EB%8A%94-%EC%9D%B4%EC%9C%A0"
ai_assisted: true
---

# 늦게 보낸 읽기가 먼저 끝나도 정상일 수 있는 이유

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

[원문](https://ariser.io/@writer_a9817d5a8de0/%EB%8A%A6%EA%B2%8C-%EB%B3%B4%EB%82%B8-%EC%9D%BD%EA%B8%B0%EA%B0%80-%EB%A8%BC%EC%A0%80-%EB%81%9D%EB%82%98%EB%8F%84-%EC%A0%95%EC%83%81%EC%9D%BC-%EC%88%98-%EC%9E%88%EB%8A%94-%EC%9D%B4%EC%9C%A0)

먼저 보낸 읽기의 결과보다 나중에 보낸 읽기의 결과가 먼저 돌아왔다. 순서를 바꾸는 회로에 오류가 있다고 단정하기 전에 AXI ID를 확인해야 한다. AXI ID ordering은 모든 요청을 하나의 줄로 세우는 규칙과 다르다. 같은 ID로 묶인 응답의 순서는 지켜야 하지만, 서로 다른 ID의 응답은 먼저 준비된 쪽이 앞설 수 있다.

ID를 거래마다 유일한 일련번호라고 생각하면 이 규칙을 잘못 구현하기 쉽다. 같은 ID로 여러 요청을 outstanding 상태에 둘 수 있다. 이때 ID 하나만으로 그중 어느 요청인지를 마음대로 고를 수 있는 것이 아니라, 그 ID 안에서 먼저 발행한 요청부터 응답해야 한다. Arm 규격은 동일 ID의 읽기 응답 순서와 쓰기 응답 순서를 각각 정의한다. [Arm IHI0022H, A5.1·A6.5.3](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/IHI0022H_amba_axi_protocol_spec.pdf)

일반 AXI4 읽기 세 개를 주소 채널의 handshake 순서대로 수락했다고 하자. 각 요청은 한 beat이며 독립된 읽기 전용 메모리 위치를 대상으로 한다. 외부에서 다른 쓰기는 없고, 예상 값은 요청 수락 전에 정해진 가상 예제다.

| 요청 | ARID | 주소 | 예상 데이터 |
|---|---:|---|---:|
| A | 3 | 0x1000 | 10 |
| B | 8 | 0x2000 | 20 |
| C | 3 | 0x1004 | 30 |

허용되는 전체 완료 순서는 A-B-C, A-C-B, B-A-C다. 공통점은 ID 3의 A가 C보다 먼저라는 것이다. B는 ID 8이므로 두 ID 3 요청 사이에도, 그 앞뒤에도 올 수 있다. B-C-A는 C가 A를 앞서므로 허용되지 않는다. 서로 다른 ID를 썼다는 말만으로 모든 요청의 순서가 자유로워지는 것은 아니다.

전역 FIFO 하나에 A, B, C를 넣고 맨 앞과만 비교하는 검증기는 B가 먼저 응답할 때 잘못 오류를 보고한다. 반대로 ID로 찾아서 어느 위치든 예상 데이터가 같은 요청을 지우는 검증기는 C의 30이 먼저 돌아온 상황을 놓칠 수 있다. 합법적인 순서 변경은 허용하고, 같은 ID 안의 불법 변경은 잡는 구조가 필요하다.

이 예제의 검증 상태는 ID별 큐로 표현하면 명확하다. ID 3의 큐에는 [A,C], ID 8의 큐에는 [B]를 넣는다. RID=8과 데이터 20이 수락되면 ID 8의 맨 앞 B와 비교하고 B를 제거한다. 다음 RID=3, 데이터 10은 A와 비교한다. 마지막 RID=3, 데이터 30은 C와 비교한다. RID만 맞는지 확인하거나 valid가 보였다는 이유만으로 제거하면 부족하다. 응답 수락은 RVALID와 RREADY가 함께 1인 경계에서 일어난다.

C의 데이터 30이 RID=3으로 먼저 오면 비교 대상은 여전히 A다. 따라서 값이 맞지 않다고 잡을 수 있다. A와 C의 예상 데이터가 우연히 같다면 숫자 비교만으로 순서를 구별하지 못하므로, 검증 자극에서 주소별 구별 가능한 값과 내부 추적을 활용할 필요가 있다. 데이터가 같다고 규약이 순서 변경을 허용한 것은 아니다.

여러 beat의 burst에서는 큐의 맨 앞 요청을 첫 데이터 한 개 뒤에 제거하면 안 된다. 그 요청의 beat 진행을 추적하고 예상 개수를 확인하며, 마지막 응답 beat의 handshake에서 거래를 끝내야 한다. RLAST가 너무 일찍 오거나 끝에서 오지 않는 상황도 검사 대상이다. 다른 ID의 beat가 그 사이에 들어오는 경우는 허용될 수 있으므로 전체 R 채널을 단순한 한 거래의 연속 구간으로 가정해서는 안 된다. [Arm IHI0022H, A5.2.1 Read data ordering](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/IHI0022H_amba_axi_protocol_spec.pdf)

ID는 읽기와 쓰기를 하나의 공통 순서로 묶지도 않는다. ARID=3으로 읽고 AWID=3으로 쓴 사실만으로 두 방향 사이의 순서가 보장되지는 않는다. 쓰기 결과를 확인한 뒤 그 값을 읽어야 하는 알고리즘이라면 필요한 선행 응답과 메모리 속성 등 별도의 순서 계약을 갖춰야 한다. 응답이 돌아오는 순서와 실제 메모리 효과를 관찰하는 순서도 구별해서 읽어야 한다. [Arm IHI0022H, A6.1 AXI ordering model overview](https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/IHI0022H_amba_axi_protocol_spec.pdf)

ID의 개수는 가능한 outstanding 거래 수와도 같지 않다. 가상 인터페이스가 ID별로 네 요청을 보관하도록 설계되었다면 두 ID로 여덟 요청을 추적할 수 있다. 하지만 실제 큐 깊이나 상대의 처리 능력이 그만큼이라는 보장은 없다. 같은 ID를 많이 쓰면 응답이 그 ID의 앞선 요청에 막힐 수 있고, ID를 늘리면 독립성을 얻는 대신 대응 상태와 재정렬 저장 공간이 늘어날 수 있다.

AXI ID ordering을 확인하는 출발점은 응답의 ID를 이름표로 읽는 데서 멈추지 않는 것이다. 해당 ID의 어떤 요청이 지금 맨 앞인지, 그 거래가 몇 beat까지 끝났는지 기록해야 한다. 이 방식으로 보면 늦게 보낸 요청이 먼저 끝나는 정상 병렬성과, 같은 ID의 순서를 깨는 오류를 서로 다르게 다룰 수 있다.

