프로그램 내장 방식 컴퓨터와 폰 노이만 아키텍처
프로그램과 데이터를 같은 메모리에 저장하는 프로그램 내장 방식의 원리, 역사, 병목과 현대 프로세서의 변형을 정리한다.
2026-08-14 · 최초 발행 2026-01-02
메모리에 적재된 명령어가 기계를 바꾼다
프로그램 내장 방식 컴퓨터(Stored Program Computer)는 명령어와 데이터를 같은 메모리에 저장하고, 그 명령어를 차례로 읽어 실행하는 구조다. 작업을 바꾸기 위해 하드웨어를 다시 구성해야 했던 고정 배선 방식과 달리, 프로그램을 교체하는 것만으로 컴퓨터의 동작을 바꿀 수 있다.
메모리 주소 자체만으로는 그 안의 값이 명령어인지 데이터인지 구분할 수 없다. 프로그램 카운터(PC)가 가리키는 위치의 내용을 명령어로 해석하며, PC는 보통 다음 명령어 주소로 이동한다. 분기 명령어는 이 흐름을 다른 주소로 바꾼다. 이 방식이 범용 컴퓨터와 프로그래밍 언어 기반 제어의 출발점이 됐다.
고정 배선 방식에서는 프로그램이 하드웨어에 고정돼 있어 작업을 바꾸려면 하드웨어를 재구성해야 했다. ENIAC 초기 모델의 플러그보드 수동 프로그래밍이 여기에 해당한다. 반면 프로그램 내장 방식은 메모리에 프로그램을 보관하며, 소프트웨어 교체로 작업을 변경한다. EDVAC과 EDSAC은 이 방식의 초기 구현 사례다.
EDVAC 문서에서 초기 컴퓨터까지
존 폰 노이만은 1945년 First Draft of a Report on the EDVAC에서 프로그램 내장 방식의 개념을 명시했다. 이 문서는 이진법, 순차 처리, 메모리 구조를 제안했고, CPU·메모리·입출력 장치·시스템 버스로 구성되는 폰 노이만 아키텍처의 토대가 됐다.
초기 구현은 서로 다른 의미를 가진다. EDVAC은 1949년에 완성됐으며 프로그램 내장 방식으로 설계되고 이진법을 사용한 컴퓨터다. EDSAC은 1949년 5월 완성됐고, 실제로 작동한 최초의 프로그램 내장 방식 컴퓨터로 소개된다. 케임브리지 대학의 모리스 윌크스(Maurice Wilkes)가 개발했으며 수은 지연선 메모리(Mercury Delay Line)를 사용했다.
Manchester Baby는 1948년 6월 최초 실행됐고, 프로그램 내장 방식을 처음 구현한 컴퓨터다. 톰 킬번(Tom Kilburn)과 프레데릭 윌리엄스(Frederic Williams)가 개발했으며 CRT(음극선관) 메모리를 사용했다.
범용 컴퓨터를 가능하게 한 메모리 구조
프로그램 내장 방식에서는 하드웨어를 재구성하지 않아도 하나의 기계가 다양한 작업을 수행할 수 있다. 어셈블리 언어는 기계어를 기호로 표현했고, FORTRAN·COBOL·C 같은 고급 언어는 프로그래머의 생산성을 높이는 방향으로 발전했다.
명령어와 데이터가 하나의 메모리 공간을 공유하므로 동적 메모리 할당이 가능하며, 프로그램 크기에 맞춰 메모리 활용을 조정할 수 있다. 메모리에 있는 명령어를 수정할 수 있어 초기 컴퓨터에서는 자기 수정 코드(Self-Modifying Code)도 구현할 수 있었고, 디버깅과 패치도 수월해졌다.
PC의 자동 증가와 분기 명령어는 조건부 실행, 반복문, 서브루틴을 가능하게 한다. 전자식 메모리는 진공관·트랜지스터·IC를 거치며 기계식 장치보다 수백만 배 빠른 처리 속도를 제공했고, 대량 계산 작업을 처리할 수 있게 했다.
명령어는 인출·해독·실행·저장을 반복한다
프로그램 내장 방식의 실행은 Fetch-Decode-Execute 사이클을 반복한다. Fetch 단계에서는 PC가 가리킨 메모리 주소에서 명령어를 읽어 명령어 레지스터(IR)에 넣고, PC를 다음 명령어 주소로 증가시킨다. Decode 단계에서 제어장치는 IR의 명령어를 분석해 연산 코드(Opcode)와 피연산자(Operand) 위치를 파악한다.
Execute 단계에서는 ALU가 연산을 수행하고 필요하면 메모리에 접근한다. 마지막 Store 단계에서 결과는 레지스터 또는 메모리에 기록되며 상태 플래그가 갱신된다.
ADD R1, R2, R3 명령어를 예로 들면, Fetch 단계에서 PC가 가리키는 주소(예: 0x1000)의 명령어를 IR에 저장하고 PC를 0x1004로 증가시킨다. Decode 단계는 ADD 연산과 목적지 R1, 피연산자 R2·R3를 식별한다. Execute 단계에서 ALU는 R2와 R3의 값을 더하며, Store 단계는 결과를 R1에 저장하고 필요 시 오버플로우 플래그를 갱신한다.
명령어: ADD R1, R2, R3 (R1 = R2 + R3)
1. Fetch:
- PC가 가리키는 주소(예: 0x1000)에서 명령어 인출
- IR에 "ADD R1, R2, R3" 저장
- PC를 0x1004로 증가
2. Decode:
- Opcode: ADD (덧셈)
- Destination: R1
- Operands: R2, R3
3. Execute:
- R2와 R3의 값을 ALU로 전달
- ALU에서 덧셈 수행
4. Store:
- 결과를 R1에 저장
- 오버플로우 플래그 업데이트 (필요 시)
공유 메모리가 만드는 병목과 실행 가능 데이터
명령어와 데이터가 같은 버스를 공유하면 명령어 인출과 데이터 접근을 동시에 처리할 수 없다. CPU 속도가 메모리 속도보다 빠를 때 이 구조는 폰 노이만 병목(Von Neumann Bottleneck)으로 나타난다.
캐시 메모리는 자주 사용하는 데이터를 고속 캐시에 저장해 접근 부담을 줄인다. 하버드 아키텍처는 명령어 메모리와 데이터 메모리를 분리하며, 파이프라이닝은 명령어 처리 단계를 중첩한다.
코드와 데이터의 경계가 메모리 주소만으로 구분되지 않는 점은 보안상 문제도 만든다. 데이터 영역이 명령어로 실행될 수 있고, 버퍼 오버플로우 공격이나 악성 코드 주입에 취약할 수 있다. NX bit(No-Execute bit)는 데이터 영역 실행을 금지하고, ASLR(Address Space Layout Randomization)은 주소를 무작위화하며, DEP(Data Execution Prevention)는 데이터 실행을 방지한다.
기본 구조를 보완하는 현대 프로세서
하버드 아키텍처는 명령어 메모리와 데이터 메모리를 분리해 병목을 완화하고 파이프라인 효율을 높인다. DSP와 마이크로컨트롤러에서 사용된다. Modified Harvard Architecture는 캐시 수준에서 명령어와 데이터를 분리하지만 주메모리는 통합 구조로 유지하며, 현대 프로세서의 표준이다.
슈퍼스칼라와 비순차 실행(Out-of-Order Execution)은 명령어 수준 병렬성을 활용한다. 여러 명령어를 동시에 실행하고 분기 예측 및 투기적 실행을 사용한다. 멀티코어 프로세서는 여러 CPU 코어가 독립적으로 프로그램을 실행하게 하며, 병렬 프로그래밍 모델과 다중 프로그램 동시 실행을 뒷받침한다.
소프트웨어와 현대 컴퓨팅의 기반
프로그램 내장 방식은 하드웨어 엔지니어와 프로그래머의 역할 분리, 소프트웨어 개발 방법론의 발전, 프로그래밍 언어와 도구의 진화를 이끌었다. 라이브러리·프레임워크, 운영체제·미들웨어, 오픈소스 생태계도 프로그램을 교체하고 재사용할 수 있는 환경에서 발전했다.
앨런 튜링의 보편 계산 기계(Universal Turing Machine)는 프로그램 내장 방식으로 튜링 완전성을 구현하는 연결점을 가진다. 정렬·탐색·그래프 알고리즘, 계산 복잡도 이론, 인공지능 및 기계학습 알고리즘 연구도 이 구조 위에서 실용화됐다.
데스크톱·서버·모바일 기기·임베디드 시스템·슈퍼컴퓨터는 모두 범용 컴퓨터의 연장선에 있다. 멀티태스킹과 멀티프로세싱, 가상 메모리, 파일 시스템을 갖춘 운영체제도 마찬가지다. 네트워크 프로토콜 소프트웨어, 웹 서버와 애플리케이션, 가상화와 컨테이너 기술까지 현대 컴퓨팅의 많은 구성 요소가 프로그램 내장 방식의 유연성에 기대고 있다.