컴퓨터가 작동하는 원리: 기초부터 설명하기
키 입력에서 시작하기
키보드의 ‘A’ 키를 누릅니다.
1밀리초도 채 되지 않아, 문자가 화면에 나타납니다.
간단해 보이나요? 실제로는 이 1밀리초 동안 전기 신호가 최소 6계층의 추상화를 통과하고, 수십 개의 하드웨어 구성 요소를 지나며, 여러 버스를 가로질러 이 “단순한” 상호작용을 완료합니다.
컴퓨터의 본질은 계산이 아니라 추상화입니다.
각 계층은 아래의 복잡성을 숨기고 위 계층에 깔끔한 인터페이스만 노출합니다. 이러한 추상화 덕분에 프로그래머는 트랜지스터를 통해 전자가 어떻게 흐르는지 신경 쓰지 않고 고수준 언어로 코드를 작성할 수 있습니다.
오늘 우리는 키 입력 신호의 완전한 여정을 추적하며, 컴퓨터가 추상화의 계층을 통해 어떻게 물리적 동작을 화면의 문자로 변환하는지 살펴봅니다.
첫 번째 계층: 물리적 신호에서 스캔 코드로

당신이 누르는 것은 문자가 아니라 스위치입니다.
키보드의 모든 키 아래에는 기계식 스위치가 있습니다. ‘A’ 키를 누르면 스위치가 닫히고 전류가 흐릅니다. 이것은 가장 기본적인 물리적 현실입니다 — 켜짐과 꺼짐만 있을 뿐, ’A’는 없습니다.
키보드 컨트롤러의 역할은 이 물리적 신호를 컴퓨터가 이해할 수 있는 숫자로 변환하는 것입니다.
어떻게 할까요?
매트릭스 스캔
키보드에는 100개 이상의 키가 있습니다. 각각을 컴퓨터에 연결하는 별도의 케이블이 있다면 키보드 케이블이 손가락보다 두꺼워질 것입니다. 그래서 키보드는 똑똑한 설계를 사용합니다: 매트릭스 스캔입니다.
체스판을 상상해보세요. 행과 열이 교차하고 있습니다. 각 키는 교차점에 위치합니다. 컨트롤러는 각 행에 빠르게 전원을 공급하고 각 열에 전류가 있는지 감지합니다. 행 3에 전원이 공급되었을 때 열 5가 전류를 감지하면, 행 3, 열 5의 키가 눌렸음을 의미합니다.
여기서 스캔 코드(scan code)가 나옵니다 — 키의 위치를 나타내는 숫자입니다.
’A’를 누르면 스캔 코드 0x1E가 출력됩니다. ’A’를 놓으면 0x9E가 출력됩니다 (“해제”를 나타내는 추가 상위 비트 포함).
첫 번째 계층 완료: 물리적 동작 → 디지털 인코딩.
하지만 아직 끝나지 않았습니다. 스캔 코드는 여전히 키보드 내부 버퍼에 있으며 전송되기를 기다리고 있습니다.
두 번째 계층: I/O 장치에서 메모리로

스캔 코드는 CPU에 도달해야 하지만, CPU는 키보드 입력을 기다리며 가만히 있을 수 없습니다.
CPU는 초당 수십억 번의 연산으로 작동하고, 키보드 입력은 초당 수십 번 들어옵니다. 만약 CPU가 모든 명령어 전에 “키보드 입력이 있나요?“를 확인한다면, 99.9999%의 시간이 낭비될 것입니다.
해결책은? 인터럽트 메커니즘입니다.
인터럽트: “준비되면 내게 전화해”의 하드웨어 버전
인터럽트의 설계 철학은 일상생활을 반영합니다: 배달원에게 5분마다 “택배가 도착했나요?“라고 전화하지 않습니다. 대신 배달원이 도착했을 때 전화를 합니다.
키보드 컨트롤러가 스캔 코드를 생성한 후, CPU에 인터럽트 요청(IRQ) 신호를 보냅니다.
이 신호는 인터럽트 컨트롤러(8259A 또는 현대적 등가물)를 통과하며 인터럽트 번호가 할당됩니다. 키보드는 일반적으로 IRQ1, 인터럽트 번호 0x21입니다.
CPU는 각 명령어를 실행한 후 인터럽트 신호가 있는지 확인합니다. 있으면 현재 작업을 중단하고 인터럽트를 처리합니다.
인터럽트 벡터 테이블
CPU는 키보드 인터럽트를 어떻게 처리해야 하는지 어떻게 알까요?
메모리에는 인터럽트 벡터 테이블(Interrupt Vector Table)이 있어 각 인터럽트 번호에 대한 처리기 루틴의 주소를 저장합니다. 이것은 전화번호부와 같습니다: 인터럽트 번호 0x21은 키보드 처리기의 주소에 해당합니다.
CPU가 키보드 인터럽트를 수신하면:
- 현재 프로그램 카운터(PC), 상태 레지스터 등을 스택에 푸시합니다
- 인터럽트 번호로 테이블을 조회하여 처리기 주소를 찾습니다
- 처리기로 점프하여 실행합니다
키보드 처리기는 I/O 포트(일반적으로 0x60)를 통해 스캔 코드를 읽은 후, 메모리의 키보드 버퍼에 저장합니다.
두 번째 계층 완료: I/O 이벤트 → 메모리 내 데이터.
이제 스캔 코드는 메모리에 안전하게 있습니다. 하지만 여전히 스캔 코드일 뿐, 문자 ’A’는 아닙니다.
세 번째 계층: 스캔 코드에서 문자로

스캔 코드 0x1E는 “키보드에서 A 키의 위치”를 나타낼 뿐, 문자 ’A’가 아닙니다.
왜? 같은 키라도 국가별 키보드에서 다른 문자를 나타낼 수 있기 때문입니다. 미국인이 누르면 ’A’를 얻고, 프랑스인이 누르면 ’Q’를 얻습니다 (키보드 레이아웃이 다릅니다).
스캔 코드를 문자로 변환하는 것은 운영체제의 역할입니다.
입력 서브시스템
현대 운영체제는 모두 입력 서브시스템(Input Subsystem)을 가지고 있으며, 다음을 처리합니다:
- 커널 버퍼에서 스캔 코드 읽기
- 현재 키보드 레이아웃에 따라 문자로 변환
- 수정자 키 처리 (Shift+A = 대문자 ‘A’, Ctrl+C = 복사 명령)
- 현재 활성 창으로 문자 전달
이 변환에는 키보드 레이아웃 매핑 테이블이 포함됩니다. Windows 레지스트리에는 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts가 있어 다양한 언어의 매핑을 저장합니다.
변환 후, 문자 ’A’는 메시지 큐에 배치되어 애플리케이션이 읽기를 기다립니다.
세 번째 계층 완료: 하드웨어 종속 인코딩 → 통합 문자 인코딩.
네 번째 계층: 문자에서 픽셀로

애플리케이션은 문자 ’A’를 받아 화면에 표시해야 합니다.
하지만 당신이 보는 것은 문자가 아니라 픽셀입니다.
모니터는 픽셀만 이해합니다 — 각 점이 어떤 색인지. 문자 ’A’는 일련의 픽셀로 구성된 패턴이며, 폰트 파일에 저장되어 있습니다.
폰트 렌더링
’A’를 입력하면 애플리케이션은:
- 폰트 파일을 찾습니다 (예: Microsoft YaHei, SimSun)
- ’A’의 글리프 설명(벡터 곡선 또는 비트맵)을 가져옵니다
- 폰트 크기에 따라 글리프를 확대/축소합니다
- 래스터화: 벡터 곡선을 픽셀 그리드로 변환합니다
- 안티앨리어싱을 적용하여 가장자리를 부드럽게 만듭니다
이 픽셀 데이터는 비디오 메모리(VRAM) — 그래픽 카드의 메모리 — 에 기록됩니다.
VRAM에서 화면으로
그래픽 카드의 디스플레이 컨트롤러는 초당 60회(60Hz)의 속도로 VRAM에서 데이터를 읽어 비디오 신호로 변환하여 모니터로 보냅니다.
모니터는 신호를 수신하고 각 픽셀의 색상을 제어하며, 당신은 문자 ’A’를 보게 됩니다.
네 번째 계층 완료: 문자 인코딩 → 픽셀 행렬.
다섯 번째 계층: CPU가 이 명령어들을 어떻게 실행하는가

위에서 언급된 모든 작업 — 스캔, 인터럽트, 변환, 렌더링 — 은 궁극적으로 CPU에 의해 실행되어야 합니다.
CPU는 어떻게 명령어를 실행할까요?
명령어 사이클: 인출-해독-실행
명령어 실행은 세 단계로 이루어집니다:
-
인출 (Fetch)
- 프로그램 카운터(PC)가 다음 명령어의 주소를 저장합니다
- 주소를 메모리로 보내 명령어를 가져옵니다
- 명령어를 명령어 레지스터(IR)에 저장합니다
-
해독 (Decode)
- 제어 유닛이 명령어의 연산 코드를 분석합니다
- 수행할 연산을 결정합니다 (덧셈? 로드? 점프?)
- 피연산자의 위치를 결정합니다
-
실행 (Execute)
- 산술 논리 장치(ALU)가 계산을 수행합니다
- 또는 메모리에 접근하여 데이터를 읽거나 씁니다
- 프로그램 카운터를 업데이트합니다
그런 다음 반복합니다.
예시
CPU가 ADD R1, R2, R3을 실행해야 한다고 가정합니다 (R2와 R3의 값을 더해 R1에 저장):
- 인출: 메모리에서 이 명령어의 기계어 코드를 읽습니다
- 해독: 이것이 덧셈 명령어이며, 피연산자가 R2와 R3에 있음을 인식합니다
- 실행: ALU가 R2와 R3의 값을 가산기로 보내고, 결과를 R1에 씁니다
각 명령어는 나노초 단위로 완료됩니다.
다섯 번째 계층 완료: 고수준 언어 → 기계 명령어 → 전기 신호.
추상화의 대가
추상화는 공짜가 아닙니다.
각 추상화 계층은 성능 오버헤드를 수반합니다:
- 키보드 스캔: 몇 마이크로초
- 인터럽트 처리: 수십 마이크로초
- OS 변환: 수백 마이크로초
- 폰트 렌더링: 몇 밀리초
- VRAM 쓰기: 몇 마이크로초
이 모든 것이 합쳐져 당신이 느끼는 “입력 지연(input lag)“이 됩니다. 일반적으로 10~50밀리초 사이입니다.
일반인에게 이 지연은 무시할 만합니다. 그러나 e스포츠 선수에게는 생사가 걸린 차이입니다. 그래서 그들은 기계식 키보드(더 빠른 작동), 고주사율 모니터(144Hz 이상), 유선 연결(무선은 추가 지연 발생)을 사용합니다.
한마디로
컴퓨터의 본질은 추상화입니다: 복잡성을 캡슐화하고, 간단한 인터페이스만 노출합니다.
키 입력 신호의 여정:
물리적 스위치 → 스캔 코드 → 인터럽트 → 메모리 버퍼 → 문자 인코딩 → 메시지 큐 → 폰트 렌더링 → VRAM → 픽셀
각 계층은 단 한 가지 일만 합니다: 아래 계층의 단순화된 출력을 받아 처리하고, 위 계층에 단순화된 인터페이스를 제공합니다.
바로 이 계층적 추상화 덕분에 인간은 믿을 수 없을 정도로 복잡한 컴퓨터 시스템을 다룰 수 있습니다.
프로그래머는 키보드 스캔이 어떻게 작동하는지 알 필요가 없습니다 — getchar()의 반환값만 읽으면 됩니다.
프로그래머는 그래픽 카드가 어떻게 렌더링하는지 알 필요가 없습니다 — DrawText() 함수만 호출하면 됩니다.
추상화의 힘은 복잡성을 관리 가능하게 만드는 데 있습니다.
