Follow-up to the bilingual-structure commit: docs/adr-ko/ now holds only Korean versions (24 files translated from English placeholders), ADR-0013 slug uses kebab-case in both folders, and the verify tool allows translated parenthetical commentary in the Status block. - Translate 24 English files in docs/adr-ko/ to Korean. The previous bilingual-structure commit had left these as English copies because their source content was already English; this commit fulfills the policy that docs/adr-ko/ contains only Korean. - Rename ADR-0013 in both adr/ and adr-ko/ from ver-verification_strategy.md to ver-verification-strategy.md (kebab-case consistency with other ADRs). - CLAUDE.md (ADR Translation Discipline): clarify that only the Status lifecycle keyword (Accepted / Proposed / Stub / Draft / Superseded by ADR-NNNN / Merged into ADR-NNNN) must match across EN and KO; parenthetical commentary and trailing list items may be translated. - tools/verify_adr_lang_pairs.py: replace byte-equal Status check with normalize_status_keyword() which strips parenthetical commentary and takes only the first non-empty line. - tests/test_verify_adr_lang_pairs.py: update existing test names, add coverage for translated parenthetical, translated trailing list, and Superseded-by-NNNN keyword equality. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
12 KiB
ADR-0034: HBM 컨트롤러 내부 설계
Status
Accepted
Context
HbmCtrlComponent는 큐브 NOC의 말단(leaf)에 위치하는 PE별 HBM
파티션 엔드포인트이다. 토폴로지 노드
sip{S}.cube{C}.hbm_ctrl.pe{idx} 아래에 PE마다 하나의 인스턴스가
생성되며 해당 PE의 라우터에 연결된다 (ADR-0017 D4). 본 컴포넌트는
의사 채널(PC, pseudo-channel)별 스케줄링, 버스트 단위 커밋 타이밍,
주소 기반 PC 선택, 그리고 응답을 요청자에게 되돌리는 라우팅을
모델링한다.
본 ADR은 현재 구현된 컴포넌트를 문서화한다. ADR-0017 D4/D8은 HBM CTRL이 어디에 부착되는지와 어떤 집계 대역폭을 제공해야 하는지를 정의한다. ADR-0033 D1/D2는 HBM 모델링의 *어떤 정밀도(fidelity)*가 범위에 포함되는지를 정의한다. 본 ADR은 그 둘 사이의 공백 — 인스턴스별 내부 스케줄링 모델을 채운다.
Decision
D1. 역할
HbmCtrlComponent는 PE별 HBM 파티션 엔드포인트이다. PE당 하나의
인스턴스(큐브당 기본 8개, cube.memory_map.hbm_slices_per_cube로 설정)가
cube_mesh.yaml의 peX.hbm 부착 목록을 통해 해당 PE의 라우터에 연결된다
(ADR-0017 D4). 기본 n:1 채널 매핑(ADR-0017 D8)에서는 인스턴스가
channels_per_pe개의 의사 채널을 하나의 엔드포인트로 집계한다.
본 컴포넌트는 다음을 모델링한다:
- PC별 스케줄링(D2) 및 R/W 명령 버스 공유.
- 주소 기반 PC 선택(D3).
- 버스트 단위 커밋 타이밍(D4).
- Flit 인지 per-flit PC 커밋 및 비동기 finalize(D5, D6).
- 읽기 데이터 드레인(drain)을 위한 명령 전용 Transaction 처리(D7).
- 요청자에게 되돌리는 응답 라우팅(D8).
다음은 모델링하지 않는다:
- Bank 수준의 row-buffer 충돌, refresh, ECC, 열 스로틀링 (ADR-0033 D3).
- 자신의 라우터 엣지를 넘어가는 PE 간 HBM 경합(라우터 메시가 처리 — ADR-0017 D3).
- 1:1 채널 모드(ADR-0017 D8 향후 작업).
D2. PC별 스케줄링 모델
start()에서 초기화되는 인스턴스별 상태:
_pc_avail: list[float]— 각 PC가 다음에 자유로워지는 가장 빠른 시뮬레이션 시각; 길이num_pcs, 초기값 0.0._pc_last_dir: list["R"|"W"|None]— 각 PC의 마지막 커밋 방향, 스위치 페널티 감지에 사용(D4); 초기값None.
num_pcs와 burst_bytes는 각각 양의 2의 거듭제곱이어야 주소 기반 PC
선택(D3)이 시프트와 마스크로 축약된다.
읽기와 쓰기 요청은 PC별로 동일한 _pc_avail 슬롯을 공유한다 — 실제 HW에서
PC별 명령 버스는 읽기와 쓰기 트래픽이 공유하므로, PC k에 쓰기를 발행하면
PC k에 대한 후속 읽기가 정확히 버스트 시간만큼 블록된다.
요청의 방향 dir은 요청 타입으로부터 추론된다:
MemoryWriteMsg→"W".is_write=True인PeDmaMsg→"W".- 그 외 전부(
MemoryReadMsg, 읽기PeDmaMsg) →"R".
D3. 주소 기반 PC 선택
접근에 대한 PC 인덱스는 접근 주소로부터 시프트와 마스크로 도출된다:
pc_shift = log2(burst_bytes) # 기본값 8 (burst=256B)
pc_mask = num_pcs - 1 # 기본값 7 (8 PCs)
pc = (address >> pc_shift) & pc_mask
대안적인 (burst_bytes, num_pcs) 쌍과의 정합성을 유지하기 위해
start()에서 토폴로지 설정으로부터 한 번 계산된다. 정규 기본값
(256, 8)에서는 PC 선택 필드가 HBM 바이트 오프셋의 비트 [10:8]에
배치된다: 비트 [7:0]은 버스트 내부(같은 PC), 비트 [10:8]은 3비트
PC 인덱스, 비트 [36:11]은 PC 슬라이스 내부의 row/bank/column이다
(phyaddr.py 주석 참조).
주소 기반 스트라이핑은 — 주소를 보지 않는 전역 라운드로빈과 달리 — 오프셋이 분리된 동시 전송들에 대해 PC 병렬성을 보존한다: 각 전송의 버스트는 자신의 바이트 주소가 함의하는 PC 집합 위에 결정론적으로 떨어지므로, 분리된 영역에 접근하는 멀티 PE 워크로드가 단일 PC에서 충돌하지 않는다.
D4. 버스트 단위 시간 및 PC 커밋 타이밍
단일 PC 커밋에 걸리는 시간:
chunk_time = burst_bytes / pc_bw_gbs # ns
burst_bytes(기본 256)는 flit 크기와 일치하는 버스트 단위이다 (ADR-0033 D1).pc_bw_gbs는 빌더에서 도출된다:hbm_to_router_bw_gbs / num_pcs(topology/builder.py). 이는 PE당 집계 대역폭이 라우터-HBM 링크 대역폭과 같아야 한다는 ADR-0017 D8의 불변식을 강제한다.
방향 dir로 PC pc에 도착한 접근에 대한 PC별 커밋 스케줄링:
switch_cost = switch_penalty_ns
if pc_last_dir[pc] not in (None, dir) else 0
start = max(env.now, pc_avail[pc]) + switch_cost
finish = start + chunk_time
pc_avail[pc] = finish
pc_last_dir[pc] = dir
기본 switch_penalty_ns = 0 — 이상적인 HBM 스케줄러가 R/W 스위칭
비용을 분할 상환한다는 Tier 0 가정(ADR-0033 D2). 0이 아닌 값은
교차마다 발생하는 비관적 비용을 모델링한다.
D5. Flit 인지 per-flit PC 커밋 (주 경로)
_handle_flit이 주 워커 경로이다. 각 도착 Flit에 대해:
- 트랜잭션의 첫 번째 flit인 경우(
tid = id(txn)가_txn_state에 없는 경우):run(env, nbytes)를 통해overhead_ns를 한 번 적용 — 헤더 디코드 모델, first-flit overhead 패턴(ADR-0033 D1)._txn_state[tid] = {"last_finish": env.now}로 초기화.
pc = _pc_for_address(flit.address)를 계산(D3).- 요청 방향(D2)을 사용하여 PC별 스케줄(D4)을 적용.
state["last_finish"] = max(state["last_finish"], finish)로 갱신.flit.is_last이면:_txn_state[tid]를 pop하고_finalize_txn을 spawn(D6).
per-flit 주소 인지 커밋이 분리된 HBM 오프셋으로 향하는 동시 멀티 PE 트래픽이 서로 다른 PC를 통해 병렬로 파이프라인되도록 하는 메커니즘이다.
D6. 트랜잭션별 비동기 finalize
트랜잭션의 마지막 flit이 스케줄링되고 나면, finalize는 별도로 spawn된 프로세스에서 실행된다:
def _finalize_txn(env, txn, last_finish):
wait = last_finish - env.now
if wait > 0:
yield env.timeout(wait)
yield from _send_response(env, txn)
_handle_flit은 이를 env.process(...)로 spawn한 뒤 즉시 반환하므로,
마지막 PC 커밋이 드레인되는 동안에도 워커는 다음 inbox 메시지를 집어들
수 있다.
이 분리가 없다면 — 즉 워커 자신이 yield env.timeout(wait)를 한다면 —
서로 다른 PC에 떨어지는 주소를 가진 동시 단일 flit 트랜잭션들도 결국
워커 내부에서 각각 chunk_time만큼 직렬화되어, D3와 D5가 노출하려고
설계한 PC 병렬성을 숨겨버린다.
D7. 명령 전용 트랜잭션을 위한 non-flit 폴백
_handle_txn은 inbox가 Flit이 아닌 Transaction을 전달할 때 실행된다.
이는 와이어가 flit으로 분할하지 않는 명령 전용 요청에 대한 경로로 —
대표적으로 명령 트랜잭션이 nbytes=0을 운반하는 MemoryReadMsg가
해당한다(데이터 드레인은 HBM CTRL 후처리에서 모델링되며, 인바운드
flit으로 모델링되지 않는다).
절차:
work_bytes = txn.nbytes if txn.nbytes > 0 else int(request.nbytes or 0)— 읽기 명령의 경우 작업량은 요청으로 결정된다.work_bytes > 0이면n_chunks = ceil(work_bytes / burst_bytes), 아니면 0.- 둘 다 > 0일 때
chunk_interval = drain_ns / n_chunks— 청크는drain/n_chunksns 간격으로 시간상에 스케줄링되어 병목 링크의 데이터 도착 속도를 모델링한다(ADR-0033 D1 청크 루프 드레인). overhead_ns를 위해run(env, txn.nbytes)를 한 번 적용.- 각 청크
i에 대해chunk_intervalns만큼 진행한 뒤pc = _pc_for_address(base_address + i * burst_bytes)로 D4 스케줄을 적용. - 모든 청크 스케줄링 후
last_finish - env.now만큼 대기한 다음_send_response를 호출.
_handle_txn은 _handle_flit과 동일한 _pc_avail / _pc_last_dir
상태를 공유한다 — 두 경로에 걸쳐 PC 스케줄링의 단일 진실 원천이 정확히
하나만 존재한다.
D8. 응답 라우팅
_send_response는 요청 타입과 경로 형상에 따라 디스패치한다:
| 경우 | 트리거 | 응답 |
|---|---|---|
| PE_DMA | isinstance(txn.request, PeDmaMsg) |
신규 역방향 경로 Transaction(is_response=True, nbytes=0), 동일한 done |
| Bypass — Memory Read | "m_cpu" not in any(txn.path) AND MemoryReadMsg |
nbytes=request.nbytes(데이터 반환)인 역방향 경로 Transaction |
| Bypass — Memory Write | "m_cpu" not in any(txn.path) AND not Memory Read |
txn.done.succeed() (쓰기는 로컬에서 완료) |
| 기본 | 그 외 | 역방향 경로상의 신규 ResponseMsg(correlation_id, request_id, src_cube, src_pe, success=True) |
"bypass" 분류는 ADR-0015 D4에서 정의된 Memory R/W 패브릭 경로(PCIE_EP → io_noc → ucie → 큐브 라우터 → hbm_ctrl, M_CPU 미경유)와 일치한다. PE_DMA 케이스는 내부 루프 DMA를 빠르게 유지하기 위한 전용 역방향 경로이다 (PE_DMA 읽기/쓰기는 ResponseMsg 봉투를 합성하지 않는다).
모든 역방향 경로 케이스에서, 응답 Transaction은
out_ports[reverse_path[1]] — 기록된 정방향 경로를 따라 되돌아가는 첫
홉 — 에 put된다. reverse_path의 엔트리가 2개 미만이면(축퇴된 경로),
원래의 txn.done이 직접 시그널된다.
D9. 설정 가능한 속성
| 속성 | 기본값 | 출처 | 비고 |
|---|---|---|---|
num_pcs |
8 | 토폴로지 큐브 hbm_ctrl.attrs |
2의 거듭제곱이어야 함 |
pc_bw_gbs |
32.0 | 빌더 도출: hbm_to_router_bw_gbs / num_pcs |
ADR-0017 D8 불변식 강제 |
burst_bytes |
256 | 토폴로지 attrs | 2의 거듭제곱이어야 함; flit_bytes와 동일(ADR-0033 D1) |
switch_penalty_ns |
0.0 | 토폴로지 attrs | Tier 0 기본값; 0이 아니면 비관적 R/W 스위칭 모델링 |
efficiency |
1.0 | 토폴로지 attrs | 빌더 시점에 hbm_to_router_bw_gbs에 적용(라우터 엣지 BW 스케일링만) |
overhead_ns |
0.0 | 토폴로지 attrs | First-flit 디코드 오버헤드(D5) |
pc_bw_gbs는 yaml 측 중복 없이 PE당 집계 대역폭을 라우터-HBM 링크
대역폭과 일치시키기 위해 직접 설정되지 않고 topology/builder.py에서
도출된다.
Consequences
Positive
- 주소 기반 PC 선택은 주소를 보지 않는 라운드로빈이 무너뜨릴 멀티 스트림 HBM 병렬성을 보존한다 — 분리된 HBM 영역을 갖는 멀티 PE 워크로드에서 중요하다.
- Flit 인지 경로(D5) + 비동기 finalize(D6)는 웜홀 파이프라이닝을 보존하며, 연속적인 단일 flit 트랜잭션에 대해 PC 병렬성을 노출한다.
- PC 스케줄링의 단일 진실 원천(D4 메커니즘이 D5 flit 경로와 D7 청크 루프 경로 모두에서 사용됨).
- 빌더 도출
pc_bw_gbs가 yaml 규율이 아닌 코드에서 ADR-0017 D8을 강제한다.
Negative
- PC 내부의 bank 수준 충돌 모델링이 없음; bank/row-buffer 재사용에 주소-무관(ADR-0033 D3).
- HBM 스케줄러 없음(FR-FCFS / write-buffer / watermark drain); PC당 고정
FIFO. 버스티한 혼합 R/W는
switch_penalty_ns로 근사화된다 (ADR-0033 D2). _txn_state는id(txn)로 키를 잡는 일반 dict이다; 동시 트랜잭션마다 in-flight 상태가 누적되며is_last시에만 제거된다. 현재 워크로드에는 충분하다.
Links
- ADR-0001 (물리 주소 레이아웃 — PC 비트 필드 주석)
- ADR-0015 D4 (Memory R/W 패브릭 경로 — bypass 응답 케이스)
- ADR-0017 D4 (PE별 HBM 파티셔닝 — PE 라우터로의 부착)
- ADR-0017 D8 (HBM 채널 매핑 모드 — 본 ADR이 구현하는 n:1 집계)
- ADR-0017 D9 (AddressResolver —
hbm_ctrl.pe{pe_id}엔드포인트 해석) - ADR-0033 D1 (정확한 모델링 — PC별 병렬성, 스위치 페널티, flit 인지 PC 커밋, first-flit 오버헤드, 청크 루프 드레인)
- ADR-0033 D2 (스위치 페널티 기본값 0 — 이상적 스케줄러의 분할 상환)