메모리 컨트롤러와 LPDDR
스마트폰 사양표에는 "LPDDR5X 8533 MT/s"라고 적혀 있다. 64비트 버스라면 초당 68 GB다. 그런데 실제로 게임을 돌리며 재 보면 그 숫자의 60~80%밖에 나오지 않는다. 나머지는 어디로 갔을까? 답은 DRAM이라는 기억 장치의 독특한 생김새에 있다. DRAM은 수십억 개의 작은 축전기에 전하를 담아 두는데, 그 전하는 저절로 새어 나가고, 한 번에 한 행씩만 꺼내 볼 수 있으며, 행을 바꿀 때마다 수십 ns를 기다려야 한다. 이 까다로운 창고를 관리하는 사람이 SoC 안의 메모리 컨트롤러(Memory controller)다. 이 장에서는 셀 하나에서 시작해 컨트롤러가 CPU·GPU·카메라·디스플레이의 요청을 어떤 순서로 처리하는지 직접 스케줄링해 본다.
- 1T1C DRAM 셀이 전하로 비트를 저장하고, 누설 때문에 리프레시가 필요한 이유를 온도와 함께 설명한다.
- 채널·뱅크·행·열 구조와 주소 사상이 접근 성능에 주는 영향을 확인한다.
- 행 버퍼 적중·빈 뱅크·충돌의 ACT·RD·PRE 명령 순서와 tRCD·CL·tRP·tRAS를 타이밍 그림으로 읽는다.
- FCFS·FR-FCFS·QoS 스케줄링이 행 적중률·대역폭·지연·실시간 마감에 주는 효과를 시뮬레이터로 비교한다.
- 최대 대역폭을 계산하고, 리프레시·행 충돌·읽기/쓰기 전환이 실효 대역폭과 비트당 에너지를 깎는 몫을 어림한다.
새는 양동이: 1T1C DRAM 셀
5장의 SRAM 셀은 트랜지스터 여섯 개로 1비트를 붙잡아 둔다. DRAM은 훨씬 단순하다. 트랜지스터 하나와 축전기 하나, 이른바 1T1C 셀이다. 축전기에 전하가 차 있으면 1, 비어 있으면 0이다. 셀이 작으니 같은 면적에 SRAM보다 수십 배 많은 비트를 담을 수 있다. 스마트폰의 12 GB 메모리를 SRAM으로 만들 수 없는 이유다.
대가는 두 가지다. 첫째, 축전기의 전하는 접합 누설과 트랜지스터의 미세한 누설 전류로 저절로 빠져나간다. 그래서 일정 시간마다 모든 셀을 읽어 다시 채워 주는 리프레시(Refresh)가 필요하다. 둘째, 셀의 전하는 아주 작아서(수 fF) 읽으려고 비트라인에 연결하는 순간 전하가 비트라인과 나뉘어 값이 망가진다. 이를 파괴적 읽기라 하고, 감지 증폭기가 읽은 값을 곧바로 다시 써 넣어야 한다. 아래 셀로 실험해 보자. 누설은 온도가 10°C 오를 때마다 대략 두 배로 빨라진다.
대부분의 셀은 수 초 이상 전하를 유지하지만, 칩 하나에 수백억 개의 셀이 있으니 가장 약한 셀이 리프레시 주기를 정한다. DDR4는 64 ms, LPDDR4·LPDDR5와 DDR5는 32 ms 안에 모든 행을 한 번씩 리프레시하도록 규정한다. 컨트롤러는 이 일을 한꺼번에 하지 않고, 약 3.9 µs마다 REF 명령을 하나씩 보내 몇 행씩 나눠 처리한다(8,192번이면 한 바퀴).
창고의 구조: 채널·뱅크·행·열
DRAM 칩 안의 셀들은 거대한 2차원 배열로 놓여 있다. 가로줄 하나가 행(Row, 페이지), 세로줄이 열(Column)이다. 이런 배열이 여러 개 있어 서로 독립적으로 움직이는데, 이 단위를 뱅크(Bank)라 한다. LPDDR5X는 16비트 폭 채널(Channel) 하나에 뱅크 16개(뱅크 그룹 4개 × 4)를 두고, 행 하나는 2 KB다. SB-1은 이런 채널 네 개를 PHY 네 개로 붙여 64비트 폭을 만든다.
컨트롤러는 물리 주소를 쪼개 채널·뱅크·행·열을 정한다. 어느 비트를 어디에 쓰느냐, 즉 주소 사상(Address mapping)에 따라 같은 프로그램도 성능이 크게 달라진다. 아래에서 한 채널(1 GB)의 주소를 바꿔 보고, 사상 방식을 바꿔 연속한 16번의 접근이 어느 뱅크로 가는지 보자.
| 항목 | LPDDR5X (대략, 2023~2025년) | 뜻 |
|---|---|---|
| 채널 폭 | 16비트 | 스마트폰은 보통 4채널 = 64비트 |
| 뱅크 | 16 (4 그룹 × 4) | 독립적으로 행을 열 수 있는 단위 |
| 행(페이지) 크기 | 2 KB | ACT 한 번에 감지 증폭기로 옮겨지는 양 |
| 버스트 길이 | BL16 (32 B) | RD 명령 하나로 오가는 데이터 |
| 핀당 속도 | 8533 MT/s (최대 ~10.7 GT/s) | 데이터 핀 하나가 초당 옮기는 비트 |
| tRCD / tRP / tRAS | ~18 / ~18 / ~42 ns | 행 열기 / 닫기 / 최소 열림 시간 |
| 리프레시 | tREFI ≈ 3.9 µs, 32 ms | REF 간격, 전체 한 바퀴 시간(85°C 이하) |
| I/O 전압 | VDDQ ≈ 0.5 V | 낮은 진폭으로 I/O 에너지를 아낀다 |
행 버퍼: 한 번에 한 행만 꺼내 볼 수 있다
뱅크의 데이터를 읽으려면 세 단계를 거친다. ① ACT(활성화): 행 주소를 주면 그 행의 셀 2 KB가 모두 비트라인을 거쳐 감지 증폭기에 걸린다. 이 감지 증폭기 줄을 행 버퍼(Row buffer)라 한다. 행이 열리기까지 tRCD가 걸린다. ② RD(읽기): 열 주소를 주면 행 버퍼에서 32 B를 골라 CL(CAS 지연) 뒤에 데이터 핀으로 내보낸다. ③ PRE(프리차지): 다른 행을 열려면 지금 행을 닫고 비트라인을 다시 충전해야 한다. tRP가 걸리고, 행은 열린 뒤 최소 tRAS 동안은 닫을 수 없다(파괴적 읽기 후 셀에 값을 다시 써 넣는 시간).
그래서 요청은 세 종류로 나뉜다. 원하는 행이 이미 열려 있으면 행 적중(Row hit)으로 CL만 기다리면 된다. 뱅크가 닫혀 있으면 tRCD + CL, 다른 행이 열려 있으면 행 충돌(Row conflict)로 tRP + tRCD + CL이 걸린다. 아래에서 요청을 쌓아 명령 타이밍을 직접 만들어 보자.
DRAM 명령 타이밍 만들기
열린 페이지는 다음 요청이 같은 행일 것이라고 "내기"를 하는 셈이다.
답 보기
닫힌 페이지가 조금 빠르다. 매번 다른 행이니 열린 페이지의 내기는 늘 지고, 다음 요청이 온 뒤에야 PRE를 시작해 tRP를 고스란히 기다린다. 닫힌 페이지는 읽자마자 미리 닫아 두므로 다음 요청은 tRCD + CL만 기다린다. 반대로 "적중 연속"에서는 열린 페이지가 압도적으로 빠르다. 실제 컨트롤러는 요청 큐를 들여다보고 같은 행 요청이 남아 있는지, 일정 시간 동안 아무도 그 행을 찾지 않는지 보고 행을 닫을 때를 정한다(적응형 페이지 정책).
누구를 먼저 보낼까: 메모리 컨트롤러 스케줄링
SoC의 메모리 컨트롤러에는 CPU 코어, GPU, 카메라 ISP, 디스플레이 엔진, NPU의 요청이 NoC(8장)를 거쳐 한꺼번에 몰려든다. 컨트롤러는 이 요청들을 큐에 모아 두고, 매 클럭 "지금 보낼 수 있는 명령" 가운데 하나를 고른다. 이 선택이 대역폭과 지연을 좌우한다.
- FCFS(First-come first-served): 가장 오래된 요청의 명령부터. 공평해 보이지만, 다른 요청이 쓰려던 열린 행을 닫아 버리는 일이 잦다.
- FR-FCFS(First-ready FCFS): 행 적중이라 바로 RD를 보낼 수 있는 요청을 먼저, 그다음 오래된 순. 행 적중률과 대역폭이 크게 오른다. 1990년대 말 제안된 뒤 사실상 표준이 되었다.
- QoS 우선순위(Quality of service): FR-FCFS에 마스터별 우선순위와 마감을 더한다. 디스플레이처럼 정해진 시각까지 데이터가 와야 하는 실시간 요청이 늦어지면 최우선으로 끌어올리고, 지연에 민감한 CPU를 대역폭만 많이 쓰는 GPU보다 앞세운다.
메모리 컨트롤러 스케줄러 (채널 하나, 뱅크 8개)
몇 가지 실험을 해 보자. ① FCFS → FR-FCFS: 행 적중률이 눈에 띄게 오르고 같은 부하에서 GPU 지연이 준다. ② 주소 사상을 행:열:뱅크로 바꾸면 순차 흐름이 여러 뱅크로 퍼져 뱅크 병렬성이 커진다. 대신 각 뱅크의 열린 행을 여러 흐름이 나눠 쓰게 되어 충돌이 늘 수 있다. XOR은 흐름끼리 같은 뱅크에서 부딪히는 일을 줄인다. ③ GPU 부하를 70% 이상으로 올리면 큐가 가득 차고, FR-FCFS에서는 행 적중을 몰아주느라 디스플레이 요청이 굶어 마감 위반이 생긴다. QoS로 바꾸면 위반이 사라지는 대신 GPU가 조금 손해를 본다.
한 마스터가 같은 행을 계속 두드린다고 생각해 보자.
답 보기
같은 행을 연달아 요청하는 스트리밍 마스터(GPU)가 다른 행을 원하는 요청(CPU, 디스플레이)을 오래 굶길 수 있다. 공정성 문제와 실시간 마감 위반이다. 실제 컨트롤러는 행 적중을 몇 번 연속 처리하면 강제로 다른 요청을 섞고(적중 한도), 요청이 일정 나이를 넘으면 우선순위를 올리고(에이징), 마스터별 대역폭 예산과 QoS 등급을 둔다. 스마트폰 SoC는 NoC와 컨트롤러가 함께 QoS 표식을 주고받는다.
늦으면 화면이 깨진다: 실시간 마스터와 QoS
CPU 요청이 조금 늦으면 프로그램이 조금 느려질 뿐이다. 하지만 디스플레이 엔진은 다르다. 120 Hz 화면은 8.3 ms마다 한 장을 패널로 내보내야 하고, 그동안 한 줄 한 줄을 정해진 속도로 읽어 간다. 엔진 안에는 작은 버퍼(FIFO)가 있어 DRAM 지연의 들쭉날쭉함을 흡수하지만, 버퍼가 바닥나면(언더플로(Underflow)) 그 순간 화면에 줄이 가거나 깜빡인다. 카메라 ISP도 센서가 쏟아내는 데이터를 놓치면 프레임을 잃는다. 이런 마스터를 실시간 마스터라 부른다.
QoS를 켜면 디스플레이 요청은 큐에서 다른 요청을 앞지르므로 대기 시간이 부하와 거의 무관해진다. 이처럼 SoC는 마스터마다 등급을 매긴다. 디스플레이·카메라·오디오처럼 마감이 있는 것은 실시간, CPU처럼 지연에 민감한 것은 저지연, GPU·NPU·DMA처럼 처리량만 중요한 것은 최선 노력(best effort)으로 다룬다. 실시간 마스터는 자기 버퍼 수위를 신호로 보내, 버퍼가 비어 갈수록 우선순위를 스스로 올리기도 한다.
68 GB/s는 어디로 사라지나: 대역폭과 리프레시
DRAM의 최대 대역폭은 단순한 곱셈이다. 데이터 핀 하나가 초당 옮기는 횟수(MT/s, 초당 백만 번 전송)에 버스 폭을 곱하고 8로 나눈다.
읽기·쓰기 전환이 왜 손실일까? 데이터 핀은 양방향이라, 읽다가 쓰려면 DRAM 쪽 출력 드라이버를 끄고 컨트롤러 쪽을 켜는 동안 버스를 비워야 한다(tWTR, tRTW). 그래서 컨트롤러는 쓰기를 쓰기 큐에 모아 두었다가 일정량이 차면 한꺼번에 처리한다(쓰기 배치). 행 충돌도 마찬가지로, 여러 뱅크에 요청을 고루 흩뜨려 한 뱅크가 행을 바꾸는 동안 다른 뱅크의 데이터를 내보내면 손실이 가려진다.
리프레시의 비용은 용량과 온도에 비례한다
리프레시 명령 하나가 처리하는 동안(tRFC) 그 뱅크들은 아무 요청도 받지 못한다. 칩 용량이 커질수록 한 번에 리프레시할 행이 많아져 tRFC가 길어지고, 온도가 85°C를 넘으면 리프레시를 2배, 4배 자주 해야 한다. 전체 뱅크를 한꺼번에 멈추는 전 뱅크 리프레시(REFab) 대신 뱅크 하나씩 돌아가며 하는 뱅크별 리프레시(REFpb)를 쓰면, 나머지 뱅크는 계속 일할 수 있다.
비트 하나 옮기는 데 드는 에너지와 메모리의 종류
1장에서 DRAM 읽기가 덧셈보다 수천 배 비싸다고 했다. 그 에너지는 세 군데에서 나온다. 행 활성화: ACT 한 번에 2 KB 행 전체의 비트라인을 충전·감지한다. 그 행에서 32 B만 쓰고 닫으면 대부분이 낭비다. 행 적중이 많을수록 활성화 에너지가 여러 접근에 나뉜다. 코어 읽기: 행 버퍼에서 데이터를 골라 칩 가장자리까지 옮기는 내부 배선. I/O: 칩 사이의 배선을 고속으로 흔드는 송수신 회로. 칩 사이가 멀고 신호가 빠를수록 비싸다.
| 종류 (대략, 2024~2025년) | 핀당 속도 | 폭 (장치당) | 대역폭 (장치·패키지당) | 비트당 에너지 | 쓰는 곳 |
|---|---|---|---|---|---|
| LPDDR5X | 8.5~10.7 Gb/s | 16비트 × 채널 수 | 64비트 패키지 ~68~85 GB/s | ~3~5 pJ | 스마트폰·노트북, 저전력 우선 |
| DDR5 | 4.8~6.4 Gb/s | DIMM 64비트 (32 × 2) | DIMM당 ~38~51 GB/s | ~5~8 pJ | PC·서버, 큰 용량·교체 가능 |
| GDDR6X/GDDR7 | 21~32 Gb/s | 32비트 | 칩당 ~84~128 GB/s | ~6~8 pJ | 그래픽 카드, 대역폭 우선 |
| HBM3/HBM3E | 6.4~9.6 Gb/s | 1024비트 | 스택당 ~0.8~1.2 TB/s | ~3~4 pJ | AI 가속기·HPC, 실리콘 인터포저 |
표는 서로 다른 설계 철학을 보여 준다. GDDR은 핀을 아주 빠르게 흔들어 대역폭을 얻지만 에너지가 크다. HBM은 핀을 천 개 넘게 깔고 대신 천천히 흔든다. DRAM 다이를 SoC 바로 옆 인터포저 위에 쌓아 배선이 mm 단위로 짧으니 가능한 일이다. LPDDR은 그 중간에서 낮은 전압(VDDQ 0.5 V), 짧은 PoP 배선, 깊은 절전 모드로 대기 전력을 최소화한다. 스마트폰은 하루 대부분 화면이 꺼진 채 기다리므로, DRAM이 스스로 리프레시하며 수 mW만 쓰는 셀프 리프레시(Self-refresh) 모드가 배터리 시간에 결정적이다.
① 주소 사상으로 요청을 채널·뱅크에 고루 흩뜨린다. ② 행 적중을 우선하되 굶는 요청이 없게 한도와 에이징을 둔다. ③ 쓰기는 모아서 한꺼번에. ④ 실시간 마스터의 마감을 QoS로 지킨다. ⑤ 리프레시는 뱅크별로, 한가할 때 미리. ⑥ 놀 때는 재빨리 절전 모드로. 이 여섯 가지가 같은 DRAM에서 대역폭 10~30%, 전력 수십 %의 차이를 만든다.
핵심 정리
- DRAM 셀은 트랜지스터 하나와 축전기 하나(1T1C)다. 전하가 새므로 32~64 ms 안에 모든 행을 리프레시해야 하고, 고온에서는 더 자주 해야 한다. 읽기는 파괴적이라 감지 증폭기가 다시 써 넣는다.
- DRAM은 채널 → 뱅크 → 행 → 열로 나뉜다. 주소 사상이 요청을 뱅크에 어떻게 흩뜨리는지가 뱅크 병렬성과 행 적중을 정한다.
- 행 적중은 CL, 빈 뱅크는 tRCD + CL, 행 충돌은 tRP + tRCD + CL을 기다린다. 열린 페이지 정책은 다음 요청이 같은 행이라는 데 거는 내기다.
- FR-FCFS는 행 적중을 먼저 처리해 대역폭을 높이고, QoS는 디스플레이 같은 실시간 마스터의 마감과 CPU의 지연을 지킨다.
- 최대 대역폭 = 전송 속도 × 폭 ÷ 8(LPDDR5X 8533 × 64비트 ≈ 68 GB/s). 리프레시·행 충돌·읽기/쓰기 전환 때문에 실효는 그 60~85%다. 비트당 에너지는 활성화·코어·I/O로 나뉘며 행 적중이 활성화 에너지를 줄인다.
확인 퀴즈
Q1. LPDDR5X 9600 MT/s, 64비트 버스의 이론 최대 대역폭은?
Q2. 원하는 뱅크에 다른 행이 열려 있을 때(행 충돌) 데이터가 나오기까지 필요한 명령 순서는?
Q3. DRAM이 리프레시를 해야 하는 근본 이유는?
Q4. FR-FCFS 스케줄러가 FCFS보다 대역폭이 높은 주된 이유는?
Q5. 디스플레이 엔진에 QoS 우선순위를 주는 이유로 가장 알맞은 것은?
Q6. HBM이 GDDR보다 핀당 속도가 낮은데도 장치당 대역폭이 훨씬 큰 이유는?