버스 구조
버스(Bus)는 CPU, 메모리, I/O 장치가 데이터를 주고받는 공유 통신 경로입니다. 하나의 버스를 여러 장치가 공유하기 때문에 누가, 언제 버스를 사용할지 조율하는 중재(Arbitration) 메커니즘이 핵심입니다.
핵심 개념
Address Bus
CPU가 접근할 메모리 주소나 I/O 포트를 전달합니다. CPU에서 메모리·I/O 방향의 단방향 버스입니다(DMA 같은 다른 버스 마스터도 주소를 보냅니다). 주소선의 수가 주소 공간의 크기를 결정합니다.
핵심 개념
Data Bus
실제 데이터를 주고받는 통로입니다. CPU↔메모리, CPU↔I/O 모두 이 버스를 사용합니다. 양방향이며 버스 폭(8/16/32/64비트)이 한 번에 전송 가능한 데이터 크기를 결정합니다.
핵심 개념
Control Bus
Read/Write 신호, 인터럽트 요청(IRQ), 버스 요청(BR)/승인(BG) 등 제어 신호를 전달합니다. 양방향이며 버스 동작 전체를 지휘합니다.
핵심 개념
버스 중재 (Arbitration)
여러 장치가 동시에 버스를 요청할 때 우선순위를 결정합니다. 중앙집중식(Centralized)과 분산식(Distributed) 방식이 있으며, 중앙집중식은 하나의 Arbiter가 순서를 정하고, 분산식은 장치들이 스스로 정합니다.
핵심 개념
Bus Master / Slave
버스 사용권을 주도적으로 요청하는 Master(CPU, DMA)와 요청을 받아 응답하는 Slave(메모리, I/O)로 역할이 나뉩니다.
핵심 개념
DMA (Direct Memory Access)
I/O 장치가 CPU를 거치지 않고 메모리에 직접 접근하는 방식입니다. 데이터를 옮기는 동안 CPU가 다른 작업을 할 수 있습니다.
버스가 공유 경로인 이유
장치마다 서로 전용선을 깔면 장치가 늘 때마다 배선이 급격히 늘어납니다. 그래서 하나의 경로를 여러 장치가 나눠 쓰는 버스가 쓰였고, 그 대신 한 번에 한 장치만 보낼 수 있어서 누가 쓸지 정하는 중재가 필요해졌습니다. CPU와 메모리 사이의 병목은 폰 노이만 구조에서 다룬 문제와 이어집니다.
숫자로 확인하기
자주 하는 오해
면접에서 이렇게 물어요
면접 질문
동기식 버스와 비동기식 버스는 무엇이 다른가요?
동기식은 모든 장치가 공통 클록에 맞춰 동작해 제어가 단순하지만 가장 느린 장치에 속도가 묶입니다. 비동기식은 요청과 응답 신호를 주고받는 핸드셰이킹으로 각 장치 속도에 맞추지만 제어가 복잡합니다.
면접 질문
버스 중재 방식에는 어떤 것이 있나요?
중재자가 하나인 중앙집중식과 장치들이 스스로 정하는 분산식으로 나뉩니다. 데이지 체인은 승인 신호를 장치 줄을 따라 순서대로 넘기는 중앙집중식의 한 형태로, 구조가 단순하지만 체인 앞쪽 장치가 유리합니다.
면접 질문
PCIe는 왜 병렬 공유 버스 대신 직렬 점대점 연결을 쓰나요?
병렬 버스는 선 사이의 신호 도착 시간 차이(스큐)와 간섭 때문에 클록을 높이기 어렵다고 알려져 있습니다. 직렬 점대점 연결은 장치마다 전용 레인을 가져 공유로 인한 대기가 없고, 레인 수를 늘려 대역폭을 키웁니다.
면접 질문
대역폭과 지연의 차이는 무엇인가요?
대역폭은 단위 시간에 옮길 수 있는 데이터 양이고, 지연은 요청 하나가 끝나기까지 걸리는 시간입니다. 큰 파일을 옮길 때는 대역폭이, 작은 요청을 자주 보낼 때는 지연이 성능을 좌우합니다.
실제 시스템에서는
lspci -t로 버스, 브리지, 장치가 이어진 트리 구조를 볼 수 있습니다. 리눅스 커널 문서에 PCI 서브시스템 설명이 있습니다.
dmidecode -t memory로 설치된 메모리 모듈의 형식과 속도(MT/s)를 볼 수 있습니다. 읽으려면 관리자 권한이 필요합니다.
함께 보면 좋은 토픽
참고 자료
C — 버스 읽기/쓰기 시뮬레이션
// 버스 구조 시뮬레이션 — Address / Data / Control Bus #include <stdint.h> #include <stdbool.h> // 메인 메모리 (256 바이트) #define MEM_SIZE 256 static uint8_t memory[MEM_SIZE]; // 버스 레지스터 — 실제 하드웨어의 버스 라인을 모델링 typedef struct { uint8_t address_bus; // Address Bus — 단방향 (CPU → 장치) uint8_t data_bus; // Data Bus — 양방향 bool read_signal; // Control Bus — READ 신호 bool write_signal; // Control Bus — WRITE 신호 bool bus_request; // Control Bus — BR (Bus Request) bool bus_grant; // Control Bus — BG (Bus Grant) } Bus; static Bus bus = {0}; // 메모리 읽기: Address Bus → READ 신호 → Data Bus로 반환 uint8_t bus_read(uint8_t addr) { bus.address_bus = addr; // 1. Address Bus에 주소 전송 bus.read_signal = true; // 2. Control Bus — READ 신호 활성화 bus.data_bus = memory[bus.address_bus]; // 3. 메모리 → Data Bus bus.read_signal = false; // 4. 신호 해제 return bus.data_bus; } // 메모리 쓰기: Address Bus → Data Bus에 값 적재 → WRITE 신호 void bus_write(uint8_t addr, uint8_t val) { bus.address_bus = addr; // 1. Address Bus에 주소 전송 bus.data_bus = val; // 2. Data Bus에 데이터 적재 bus.write_signal = true; // 3. Control Bus — WRITE 신호 활성화 memory[bus.address_bus] = bus.data_bus; // 4. 메모리에 기록 bus.write_signal = false; // 5. 신호 해제 } // 버스 중재 — I/O 장치가 버스 요청 후 승인받아 DMA 수행 void dma_transfer(uint8_t dst, uint8_t src_data) { bus.bus_request = true; // I/O: Bus Request (BR) 신호 전송 // Arbiter가 버스 승인 (현재 CPU 전송 완료 후) bus.bus_grant = true; // Arbiter: Bus Grant (BG) 신호 전송 bus.bus_request = false; // I/O가 버스 마스터로서 메모리에 직접 쓰기 (DMA) bus.address_bus = dst; bus.data_bus = src_data; bus.write_signal = true; memory[dst] = src_data; bus.write_signal = false; bus.bus_grant = false; // 버스 반환 }
Address Bus는 단방향이므로 항상 CPU(또는 현재 Bus Master)가 주소를 올립니다. Data Bus는 양방향이며 Read 시에는 메모리→CPU, Write 시에는 CPU→메모리 방향으로 흐릅니다. DMA 전송 시에는 I/O 장치가 Arbiter로부터 버스 사용권을 받아 직접 메모리에 접근합니다.
C — 데이지 체인 버스 중재 구현
// 데이지 체인(Daisy Chain) 버스 중재 // Bus Grant 신호를 장치 체인으로 순서대로 전달 #define NUM_DEVICES 4 typedef struct { int id; bool requesting; // 버스 요청 중인지 여부 bool granted; // 버스 사용권 획득 여부 } Device; Device devices[NUM_DEVICES] = { { 0, false, false }, // 우선순위 최고 { 1, false, false }, { 2, false, false }, { 3, false, false }, // 우선순위 최저 }; // Arbiter: Bus Grant를 체인 순서대로 전달 // 요청 중인 첫 번째 장치가 버스를 획득 int daisy_chain_arbitrate() { bool grant_available = true; // 초기에 Grant 신호 활성화 for (int i = 0; i < NUM_DEVICES; i++) { if (!grant_available) break; if (devices[i].requesting) { devices[i].granted = true; // 버스 사용권 부여 grant_available = false; // Grant 신호 차단 (이후 장치는 획득 불가) return i; } // 요청 없으면 Grant 신호를 다음 장치로 통과 } return -1; // 요청 장치 없음 } // 버스 사용 완료 후 반환 void release_bus(int device_id) { devices[device_id].granted = false; devices[device_id].requesting = false; }
데이지 체인 중재는 Bus Grant 신호를 장치 0번부터 순서대로 통과시킵니다. 요청 중인 장치가 신호를 받으면 그 자리에서 버스를 획득하고 이후 장치로의 신호를 차단합니다. 구조가 단순한 대신 앞 번호 장치가 지속적으로 요청하면 뒷 장치는 기아(Starvation) 상태가 될 수 있습니다.
Q1
주소 버스(Address Bus)의 역할은?
Q2
DMA(Direct Memory Access)를 사용하는 이유는?
Q3
버스 중재(Bus Arbitration)가 필요한 이유는?