본문 바로가기
TYLER SONG2026
블로그 목록
CS학습

Bus: CPU와 메모리·장치를 잇는 공유 통신 통로

버스(Bus)는 CPU, 메모리, 입출력 장치 간에 데이터와 신호를 주고받는 공유 전송 경로다. 주소, 데이터, 제어 신호를 각각 전달하는 세 종류의 버스가 함께 동작하며, 대역폭과 클럭 속도에 따라 시스템 전체 성능이 좌우된다. 여러 장치가 하나의 버스를 공유하기 때문에 중재(Arbitration) 메커니즘이 필요하다.

송민성6분 읽기

1. 개념

버스(Bus)는 컴퓨터 내부에서 CPU, 메모리, 입출력 장치 등 여러 구성 요소가 데이터를 주고받기 위해 공유하는 전기적 통로(전선 다발)다. 개별 장치끼리 일일이 전용선(point-to-point)으로 연결하는 대신, 하나의 공용 통로를 여러 장치가 시분할로 사용한다.

버스는 역할에 따라 세 가지로 나뉜다.

  • 주소 버스(Address Bus): CPU가 읽거나 쓸 메모리 주소를 전달한다. 단방향이며, 폭(비트 수)이 넓을수록 더 큰 주소 공간을 표현할 수 있다. 예를 들어 32비트 주소 버스는 2^32바이트(4GB)까지 주소를 지정할 수 있다.
  • 데이터 버스(Data Bus): 실제 데이터를 전달한다. 양방향이며, 폭이 넓을수록 한 번에 전송 가능한 데이터량이 늘어난다.
  • 제어 버스(Control Bus): 읽기/쓰기 신호, 인터럽트 신호, 클럭 신호 등 제어 정보를 전달한다.

2. 왜 사용하는가

모든 장치를 전용선으로 직접 연결하면 배선 수가 장치 수의 제곱에 비례해 늘어난다(N개 장치를 완전 연결하면 N(N-1)/2개의 선이 필요). 버스는 공유 통로 하나로 여러 장치를 연결해 배선 복잡도와 비용을 크게 줄인다. 대신 한 시점에는 하나의 장치만 버스를 점유할 수 있다는 제약이 생기고, 이를 관리하기 위한 중재 로직이 필요해진다.

3. 동작 원리

CPU가 메모리에서 데이터를 읽는 과정을 예로 들면 다음 순서로 진행된다.

  1. CPU가 주소 버스에 읽고자 하는 메모리 주소를 싣는다.
  2. CPU가 제어 버스를 통해 "읽기(Read)" 신호를 보낸다.
  3. 메모리 컨트롤러가 해당 주소의 데이터를 데이터 버스에 싣는다.
  4. CPU가 데이터 버스에서 값을 읽어들인다.

여러 장치가 버스를 요청할 때는 버스 중재기(Bus Arbiter)가 우선순위나 라운드로빈 방식으로 사용 권한을 배정한다. 대표적인 중재 방식은 다음과 같다.

  • 데이지 체인(Daisy Chain): 장치들을 우선순위 순서로 직렬 연결하고, 앞선 장치가 버스를 사용하지 않을 때 신호를 다음 장치로 넘긴다. 구현은 간단하지만 우선순위 낮은 장치가 기아(starvation) 상태에 빠질 수 있다.
  • 중앙 집중식 중재(Centralized Arbitration): 별도의 중재기가 각 장치의 요청(Bus Request)을 받아 허가(Bus Grant)를 내준다.

버스는 물리적 거리와 배선 부하 때문에 CPU 내부 클럭보다 느리게 동작하는 경우가 많고, 이 때문에 시스템 버스, 메모리 버스, 확장 버스(PCIe 등) 같은 계층 구조로 나뉘어 각기 다른 속도로 운영된다.

4. 코드 예제

실제 하드웨어 버스는 코드로 직접 제어할 대상이 아니지만, 동작 원리를 이해하기 위해 버스 중재와 트랜잭션 과정을 파이썬으로 단순 시뮬레이션할 수 있다.

python
import queue from dataclasses import dataclass from enum import Enum, auto class BusOp(Enum): READ = auto() WRITE = auto() @dataclass class BusRequest: device_id: str op: BusOp address: int data: int | None = None class SharedBus: """단일 공유 버스를 모델링. 한 번에 하나의 트랜잭션만 처리한다.""" def __init__(self): self.memory: dict[int, int] = {} self.pending: queue.Queue[BusRequest] = queue.Queue() def request(self, req: BusRequest) -> None: self.pending.put(req) def arbitrate_and_run(self) -> None: # FIFO 방식의 단순 중재: 먼저 요청한 장치가 먼저 버스를 점유한다. while not self.pending.empty(): req = self.pending.get() self._transaction(req) def _transaction(self, req: BusRequest) -> None: if req.op is BusOp.WRITE: self.memory[req.address] = req.data print(f"[WRITE] device={req.device_id} addr={req.address} data={req.data}") else: value = self.memory.get(req.address, 0) print(f"[READ] device={req.device_id} addr={req.address} value={value}") bus = SharedBus() bus.request(BusRequest("CPU0", BusOp.WRITE, address=0x10, data=42)) bus.request(BusRequest("DMA1", BusOp.READ, address=0x10)) bus.request(BusRequest("CPU0", BusOp.WRITE, address=0x20, data=7)) bus.arbitrate_and_run()

실행 결과는 다음과 같다.

text
[WRITE] device=CPU0 addr=16 data=42 [READ] device=DMA1 addr=16 value=42 [WRITE] device=CPU0 addr=32 data=7

이 코드는 실제 전기 신호 타이밍을 흉내내지는 않지만, "공유 자원에 대한 순차적 접근 + 중재"라는 버스의 핵심 개념을 논리적으로 보여준다.

5. 시간 복잡도 또는 성능 특성

버스 성능은 알고리즘적 시간복잡도가 아니라 물리적 지표로 표현된다.

  • 대역폭(Bandwidth): 데이터 버스 폭(비트) × 클럭 속도로 계산한다. 예를 들어 64비트 폭, 200MHz 버스는 이론상 최대 64bit × 200,000,000 = 12,800,000,000 bit/s = 1.6GB/s의 대역폭을 갖는다(오버헤드 제외 이론치).
  • 지연시간(Latency): 요청이 발생한 시점부터 응답이 도착하기까지 걸리는 시간으로, 버스 중재 대기 시간이 포함되면 늘어난다.
  • 버스 경합(Bus Contention): 장치 수가 늘어날수록 동시 요청이 늘어 대기 시간이 증가하고, 이는 시스템 전체 처리량 저하로 이어진다. 이 때문에 현대 시스템은 공유 버스 대신 지점 간(point-to-point) 링크와 스위치 기반 구조(PCIe, QPI 등)로 점차 옮겨가는 추세다.

6. 실무 사용 사례

  • PCIe(PCI Express): 그래픽카드, SSD, 네트워크 카드가 CPU와 통신하는 데 사용하는 고속 직렬 버스. 레인(lane) 수를 늘려 대역폭을 확장한다.
  • 메모리 버스(DDR4/DDR5): CPU와 RAM 사이의 전용 버스로, 대역폭과 지연시간이 애플리케이션 체감 성능(특히 메모리 바운드 작업)에 직접 영향을 준다.
  • I2C, SPI, UART: 임베디드 시스템에서 센서나 저속 주변장치와 통신할 때 쓰는 저속 버스 프로토콜.
  • 시스템 온 칩(SoC) 내부 버스: ARM AMBA(AXI, AHB, APB) 같은 온칩 버스 표준이 코어, 캐시, 주변장치 블록을 연결한다.

7. 주의할 점

  • 버스는 공유 자원이므로 장치 수가 늘어나면 병목(bottleneck)이 될 수 있다. 이 때문에 고성능 시스템은 버스를 계층화하거나(예: 시스템 버스와 확장 버스를 분리) 스위치 기반 구조로 대체한다.
  • 버스 폭과 클럭 속도만으로 실제 처리량을 단정할 수 없다. 프로토콜 오버헤드, 신호 대기 시간, 중재 지연이 실질 성능에 영향을 준다.
  • 소프트웨어 개발자 입장에서는 버스를 직접 제어하지 않지만, 캐시 미스가 잦은 코드나 메모리 접근 패턴이 나쁜 코드는 메모리 버스 트래픽을 늘려 성능 저하를 유발할 수 있다는 점을 인지해야 한다.

8. 핵심 정리

버스는 CPU, 메모리, 입출력 장치가 데이터를 주고받는 공유 통로이며, 주소·데이터·제어 세 종류의 버스가 함께 동작한다. 여러 장치가 하나의 통로를 나눠 쓰기 때문에 중재 메커니즘이 필수이고, 이는 성능 병목의 원인이 되기도 한다. 대역폭과 지연시간이라는 물리적 지표로 성능을 평가하며, 현대 시스템은 이 병목을 줄이기 위해 PCIe 같은 고속 직렬 지점 간 연결 구조로 점차 이동하고 있다.

© 2026 Tyler Song