# ADR-0001: 51비트 물리 주소 레이아웃 및 디코딩 계약

## Status

Accepted (Revision 2 — 2026-04-27: 구체적인 비트 레이아웃, rack_id 제거,
Tray->SIP / SIP->DIE 명칭 변경, PE/MCPU/IOCPU 서브 유닛 표.
ADR-0031을 대체함.)

## Date

2026-04-27 (original: 2026-02-27)

## Context

KernBench에는 다음과 같은 요건을 만족하는 안정적이고 파싱 가능한 물리 주소 체계가 필요하다.

- 라우팅 도메인(SIP / die / HBM / PE-resource / IOCPU)으로 디코딩 가능
- 토폴로지에 비의존적(개수를 하드코딩하지 않음)
- 교체 가능한 정책과 DI-first 컴포넌트를 지원
- 다수의 SIP, AHBM die, IO chiplet die를 통합된 공간에서 다룸

### 연혁

- 최초 ADR-0001은 `rack_id(4) + sip_id(4) + sip_seg(5) + local_offset(38)`
  로 구성된 51비트 레이아웃을 정의했다. `rack_id`는 실제로 사용된 적이 없다.
- ADR-0031(스텁)은 PE-resource 범위 분할을 요청했으나 구현되지 않았다.

Revision 2에서는 `rack_id`를 제거하고 `sip_seg`를 `die_id`로 개명하며,
PE, MCPU, CUBE_SRAM, IOCPU 리소스에 대한 구체적인 서브 유닛 표를 제공한다.
ADR-0031은 본 ADR로 대체된다.

## Decision

**PhysAddr 값 객체**와, 정수 주소를 라우팅 도메인으로 변환하는
**주소 디코딩 계약**을 정의한다.

### D1. PhysAddr는 불변 값 객체이다

- PhysAddr는 불변이며 순수한 값으로 비교 가능하다.
- 모든 할당자는 **완전히 명세된 PhysAddr**(부분적인 메타데이터가 아님)를 반환한다.
- PhysAddr를 해석하기 위해 전역 상태를 필요로 해서는 안 된다.

### D2. 51비트 물리 주소 레이아웃

51비트 물리 주소를 채택한다.

#### 2.1 최상위 주소 맵

```text
[50:47] sip_id        (4)     -- 16 SIPs
[46:42] die_id        (5)     -- 32 dies per SIP
[41: 0] local_offset  (42)    -- 4 TB per die
```

```text
50      47 46      42 41                      0
+---------+----------+-------------------------+
| sip_id  | die_id   |      local_offset       |
+---------+----------+-------------------------+
```

#### 2.2 die_id 할당

| die_id | 의미 |
|--------|---------|
| 0..15  | AHBM dies |
| 16..20 | IOCHIPLET dies |
| 21..31 | Reserved |

#### 2.3 AHBM Die 레이아웃

4 TB die-local 윈도우 중 하위 256 GB만 할당된다.

```text
[41:38] MBZ            (4)
[37]    addr_space      (1)    -- 0 = local resource, 1 = HBM memory
[36: 0] sub-address    (37)
```

| addr_space | 의미 |
|------------|---------|
| 0 | Local resource |
| 1 | HBM memory |

##### 2.3.1 HBM 윈도우 (addr_space = 1)

```text
[36:0] hbm_offset     (37)    -- 128 GB decode window
```

아키텍처상의 디코드 윈도우는 128 GB로 고정된다. 실제 구현 용량은
SKU/토폴로지에 따라 더 작을 수 있다(D4 참조).

##### 2.3.2 Resource 윈도우 (addr_space = 0)

```text
[36:34] resource_kind  (3)
[33: 0] kind_local    (34)    -- 16 GB per kind
```

| resource_kind | 의미 |
|---------------|---------|
| 000 | PE_LOCAL |
| 001 | MCPU_LOCAL |
| 010 | CUBE_SRAM |
| 011..111 | Reserved |

각 kind는 16 GB 디코드 영역을 갖는다.

##### 2.3.3 PE_LOCAL (resource_kind = 000)

```text
[33]    MBZ            (1)
[32:29] pe_id          (4)     -- 0..15
[28:25] pe_sub_unit    (4)
[24: 0] sub_offset    (25)    -- 32 MB per slot
```

16 PE x 16 서브 유닛 슬롯 x 32 MB = 8 GB 활성 디코드.

| pe_sub_unit | 이름 | 예산 |
|-------------|------|--------|
| 0 | PE_CPU_DTCM | 8 KB |
| 1 | MATH_ENGINE_DTCM | 8 KB |
| 2 | IPCQ | 256 KB |
| 3 | PE_CPU_SFR | 16 KB |
| 4 | MATH_ENGINE_SFR | 16 KB |
| 5 | DMA_ENGINE_SFR | 192 KB |
| 6 | PE_TCM | 2 MB |
| 7..15 | Reserved | -- |

##### 2.3.4 MCPU_LOCAL (resource_kind = 001)

```text
[33:30] MBZ            (4)
[29:25] mcpu_sub_unit  (5)
[24: 0] sub_offset    (25)    -- 32 MB per slot
```

1 GB 활성 디코드.

| mcpu_sub_unit | 이름 | 예산 |
|---------------|------|--------|
| 0 | MCPU_ITCM | 512 KB |
| 1 | MCPU_DTCM | 512 KB |
| 2 | IPCQ | 256 KB |
| 3 | MCPU_SFR | 8 KB |
| 4 | MCPU_DMA_SFR | 16 KB |
| 5 | MCPU_SRAM | 10 MB |
| 6..31 | Reserved | -- |

##### 2.3.5 CUBE_SRAM (resource_kind = 010)

```text
[33:25] MBZ            (9)
[24: 0] sram_offset   (25)    -- flat 32 MB
```

#### 2.4 IOCHIPLET Die 레이아웃

4 TB die-local 윈도우 중 하위 1 TB만 할당된다.

```text
[41:40] MBZ            (2)
[39: 0] chiplet_offset (40)   -- 1 TB
```

주소 범위별 영역 구분:

| 범위 | 의미 | 디코드 조건 |
|-------|---------|------------------|
| [0, 2 GB) | IOCPU resource | chiplet_offset < 0x8000_0000 |
| [2 GB, 1 TB) | UAL | chiplet_offset >= 0x8000_0000 |

##### 2.4.1 IOCPU 영역

```text
[30:27] iocpu_sub_unit (4)
[26: 0] sub_offset    (27)    -- 128 MB per slot
```

16 x 128 MB 슬롯. 2 GB 활성 디코드.

| iocpu_sub_unit | 이름 | 예산 |
|----------------|------|--------|
| 0 | IOCPU_ITCM | 512 KB |
| 1 | IOCPU_DTCM | 512 KB |
| 2 | IPCQ | 2 MB |
| 3 | IOCPU_SFR | 8 KB |
| 4 | IO_DMA_SFR | 16 KB |
| 5 | IO_SRAM | 64 MB |
| 6..15 | Reserved | -- |

##### 2.4.2 UAL 영역

서브 레이아웃은 별도 ADR에서 정의한다(TBD).

#### 2.5 주소 지정 규칙

1. MBZ 비트는 반드시 0이어야 한다. MBZ 비트가 0이 아닌 주소는
   **아키텍처적으로 유효하지 않다**. 구현체는 디코드 폴트를 발생시키거나
   오류를 반환할 수 있다 — 본 ADR은 동작을 규정하지 않는다.
2. 단순한 하드웨어 디코드를 위해 고정된 슬롯 크기를 채택한다. 실제 구현
   용량은 슬롯보다 작을 수 있다.
3. 슬롯 내에서 서브 유닛의 구현 예산을 초과하는 접근은 **아키텍처적으로
   유효하지 않다**(MBZ와 동일한 정책).

### D3. 비트필드 디코딩은 결정론적이다

정수 주소가 주어지면 필드 추출(`sip_id`, `die_id`, `kind`, `sub_unit`,
`offset`)은 순수하게 위치 기반이다. 런타임 상태가 필요하지 않다.
디코딩은 정수 주소를 결정론적으로 목적지 도메인(`sip_id`, `die_id`,
타깃 종류 HBM / PE_LOCAL / MCPU_LOCAL / CUBE_SRAM / IOCPU / UAL)으로 매핑한다.

### D4. 용량 검증은 토폴로지 설정에 의존할 수 있다

디코딩된 주소가 **구현된 용량** 안에 들어가는지(예: 특정 SKU의 HBM 96 GB)는
DI/설정을 통해 제공된 토폴로지 파라미터로 검증한다. 디코딩 자체(D3)는
토폴로지를 참조하지 않으며 — 검증 단계에서만 참조한다. 이러한 파라미터는
컴포넌트 구현이 아니라 토폴로지/설정 레이어에 존재해야 한다.

### D5. 라우팅은 원시 비트가 아닌 디코딩된 도메인을 소비한다

라우팅 정책은 디코딩된 도메인을 사용한다.

- `src` 위치 (sip / die / pe 또는 node_id)
- PhysAddr 디코딩에서 도출된 `dst` 도메인
- 크기 인지 링크 레이턴시를 위한 `size_bytes`

라우팅은 디코딩 모듈 내부를 제외하고는 원시 비트필드를 직접 들여다보아서는
안 된다.

## 고려된 대안

1. **`rack_id`(4비트) 유지**: 기각 — 실제로 사용된 적이 없으며, 4비트를
   소비함으로써 die-local 확장을 42비트(IOCHIPLET 1 TB)까지 가능하게 하는
   기회를 막는다.

2. **die당 256 GB로 균일화**: 기각 — IOCHIPLET UAL은 약 1 TB가 필요하다.
   해제된 rack_id 비트를 활용하여 42비트 local_offset을 가능하게 한다.

3. **가변 폭 die 윈도우(AHBM 256 GB, CHIPLET 1 TB를 다중 seg 스패닝으로 구현)**:
   기각 — D3(결정론적 디코딩)를 복잡하게 만든다. MBZ 패딩을 갖는 균일한
   4 TB 윈도우가 더 단순하다.

4. **모든 곳에서 원시 정수를 사용하고, 라우팅에서 임시로 디코딩**: 기각 —
   로직이 중복되고 라우팅이 일관성을 잃으며 가정이 숨겨진다.

5. **토폴로지 크기(SIP/CUBE/PE 개수)를 디코딩에 하드코딩**: 기각 —
   SPEC R3를 위반하고 교체 가능성을 깬다.

6. **디코딩을 메모리 컨트롤러나 라우터 내부에 둠**: 기각 — 정책이 컴포넌트로
   누출되며 SPEC R4 / D5를 위반한다.

## 결과

### 긍정적

- 단순한 계층적 디코더: SIP -> die -> kind -> 서브 유닛.
- 메모리(HBM)와 로컬 리소스(PE/MCPU/SRAM/IOCPU)의 깔끔한 분리.
- 결정론적 라우팅 도메인은 명확한 테스트 불변식을 가능하게 한다(SPEC R1, R5).
- 확장 가능: 11개의 예약된 die_id 슬롯, 예약된 resource_kind / 서브 유닛
  슬롯, 예약된 MBZ 비트.
- DI-first: 컴포넌트를 변경하지 않고도 디코더를 교체할 수 있다(SPEC R4).

### 트레이드오프

- power-of-2 슬롯 정렬로 인한 희소한 주소 공백.
- 큰 예약/MBZ 영역(향후 확장을 위해 의도된 것).
- 토폴로지에서 유도된 크기에 대해 명시적인 설정이 필요하다(D4).
- 안정적이고 잘 테스트된 상태로 유지되어야 하는 단일 "정통" 디코딩 모듈이
  도입된다.

## 대체 대상

- **ADR-0031 (PhysAddr PE-Resource Extension)**: 스텁 상태였음. D2.3.3-D2.3.5의
  PE_LOCAL / MCPU_LOCAL / CUBE_SRAM 서브 유닛 표가 ADR-0031에서 제시한
  목표를 충족한다.

## 구현 메모 (비규범적)

- 권장 모듈: `src/kernbench/policy/address/phyaddr.py`
- 테스트는 다음을 커버해야 한다: kind별 인코딩/디코딩 라운드트립, MBZ 강제,
  die_id 디스패치(AHBM / IOCHIPLET / 예약), 서브 유닛 경계값, 팩토리 API의
  후방 호환성.
- 팩토리 메서드: `hbm_addr`, `pe_hbm_addr`, `pe_tcm_addr`, `cube_sram_addr`는
  시그니처를 유지한다(`rack_id` 제외). `cube_id` 파라미터는 `die_id`로
  개명된다.
- 신규 팩토리: `pe_resource_addr`, `mcpu_resource_addr`, `iocpu_resource_addr`,
  `ual_addr`.

## 부록 A. 주소 예시

### A.1 AHBM HBM 접근

sip=2, die=5, HBM offset=0x1000

```text
sip_id     = 2       -> [50:47] = 0b0010
die_id     = 5       -> [46:42] = 0b00101
addr_space = 1       -> [37]    = 1 (HBM)
hbm_offset = 0x1000  -> [36:0]

51-bit addr = (2 << 47) | (5 << 42) | (1 << 37) | 0x1000
```

### A.2 AHBM PE_LOCAL -- PE3 PE_TCM, offset=0x400

```text
sip_id        = 0  -> [50:47] = 0
die_id        = 0  -> [46:42] = 0
addr_space    = 0  -> [37]    = 0
resource_kind = 0  -> [36:34] = 000 (PE_LOCAL)
pe_id         = 3  -> [32:29] = 0011
pe_sub_unit   = 6  -> [28:25] = 0110 (PE_TCM)
sub_offset    = 0x400 -> [24:0]

local_offset = (0 << 34) | (3 << 29) | (6 << 25) | 0x400
```

### A.3 AHBM MCPU_LOCAL -- MCPU_SRAM, offset=0x0

```text
sip_id        = 1  -> [50:47] = 0001
die_id        = 3  -> [46:42] = 00011
addr_space    = 0  -> [37]    = 0
resource_kind = 1  -> [36:34] = 001 (MCPU_LOCAL)
mcpu_sub_unit = 5  -> [29:25] = 00101 (MCPU_SRAM)
sub_offset    = 0  -> [24:0]  = 0

local_offset = (1 << 34) | (5 << 25)
```

### A.4 IOCHIPLET -- IOCPU IPCQ, offset=0x20000

```text
sip_id         = 1   -> [50:47] = 0001
die_id         = 17  -> [46:42] = 10001 (IOCHIPLET[1])
iocpu_sub_unit = 2   -> [30:27] = 0010 (IPCQ)
sub_offset     = 0x20000 -> [26:0]

chiplet_offset = (2 << 27) | 0x20000
                 (< 0x8000_0000 -> IOCPU region)
```

### A.5 IOCHIPLET -- UAL 영역, offset=4 GB

```text
sip_id         = 0   -> [50:47] = 0
die_id         = 16  -> [46:42] = 10000 (IOCHIPLET[0])
chiplet_offset = 0x1_0000_0000 (4 GB >= 2 GB -> UAL region)
```

## 링크

- SPEC.md: R1 (routing), R3 (configurable topology), R4 (DI-first),
  R5 (multi-domain comm)
- ADR-0031: Superseded
