컴퓨터 구조 기초

PKH·2025년 6월 4일

1. 개요


1. 공부 목적

처음 공부를 시작하면 프로그래밍 언어를 배운다. 그러나 단지 코드만 작성하는 개발자가 된다면, 아무래도 이슈가 발생할 경우 해결하기가 어려울 것이다.
이를 위해 컴퓨터 구조를 공부하며 성능, 용량, 비용 등 핵심적인 부분을 정리하려 한다.

2. 컴퓨터 구조

컴퓨터의 구조는 간단하게 분류하자면 2가지로 분류할 수 있다.
바로 컴퓨터가 이해하는 정보와 컴퓨터의 핵심 부품이다,

2-1. 컴퓨터가 이해하는 정보

컴퓨터는 데이터와 명령어로 구성되어 있다.

1) 데이터
0과 1로 이루어져 있으며 컴퓨터와 주고받는 정보이다.
숫자, 문자, 이미지, 동영상 등과 같은 정적인 정보를 포함한다.

2) 명령어
컴퓨터의 동작을 수행하도록 지시하는 정보이다.
데이터는 명령어를 위한 일종의 재료이기도 하다.

흔히 "컴퓨터는 0과 1로 이루어져 있다."고 말하는데, 이는 0과 1로만 이루어진 데이터를 가지고 컴퓨터를 동작시키기 때문에 나온 말임을 더 쉽게 이해할 수 있었다.

2-2. 컴퓨터의 핵심 부품

컴퓨터의 핵심 부품은 크게 4가지로 구분할 수 있다.
바로 CPU, RAM, 보조기억장치, 입출력장치이다.

1) CPU
인간의 뇌처럼 컴퓨터의 두뇌역할을 담당하며 명령어를 읽고 수행하는 부품이다.
CPU는 ALU(연산 처리), 제어 장치, 레지스터로 구성되어있다. 조금더 쉽게 설명하자면
ALU: 계산하는 장치
레지스터: CPU 내부 임시 저장장치
제어장치: 제어 신호를 보내고 명령어를 해석하는 장치. 제어 신호는 메모리 읽기와 메모리 쓰기 제어 신호가 존재함

2) RAM
현재 실행되는 프로그램(= 프로세스)의 데이터와 명령어를 저장하는 부품이다.
주소를 통해 값을 읽을 수 있으며 휘발성 저장장치이다.

  • 실행할 정보를 저장

3) 보조기억장치
전원이 꺼져도 보관될 프로그램을 저장하는 부품
ex) ssd, hdd, usb 등

  • 보관할 정보를 저장

4) 입출력장치
컴퓨터 외부에 연결되어 컴퓨터 내부와 정보를 교환하는 부품
ex) 키보드, 모니터, 마우스 등

5) 메인보드
위 4가지 핵심 부품들을 연결하는 판이다.
메인보드에 연결된 부품은 버스를 통해 정보를 주고받는다.
버스는 정보를 주고받는 통로이며 핵심 부품을 연결하는 버스는 시스템 버스라고 한다.

  1. 시스템 버스 내부 구성
    • 주소 버스: 주소를 주고받는 통로
    • 데이터 버스: 명령어와 데이터를 주고받는 통로
    • 제어 버스: 제어 신호를 주고받는 통로



2. 데이터


1. 0과1로 숫자를 표현하기

컴퓨터는 기본적으로 0과1로만 정보를 인지할 수 있다. 이 정보만으로 10+10, 5*7, 16/4 등의 정보를 어떻게 파악하는지는 다음을 통해 알 수 있다.

1-1. 정보 단위

컴퓨터의 기본 정보 단위는 비트이다. 이를 통해 정보를 처리한다.

1) 비트(Bit)
0과 1을 표현하는 가장 작은 정보 단위이다.
이를 통해서 컴퓨터는 다양한 정보를 해석할 수 있으며 다음과 같은 특징을 가진다.

  • n비트로는 2^n가지의 정보 표현 가능
  • 프로그램은 수 많은 비트로 이루어짐
  • 표기를 위해 비트보다 더 큰 단위를 사용 ex) 바이트, 킬로바이트, 메가바이트 등

단위 정리

  • 1바이트(byte): 8비트(bit)
  • 1킬로바이트(1kB): 1000byte
  • 1메가바이트(1MB): 1000kB
  • 1기가바이트(1GB): 1000MB
  • 1테라바이트(1TB): 1000GB

이전에는 1000개가 아니라 1024씩 묵었으나, 현재는 이 24개의 차이가 정보가 커지면서 차이가 발생하기에 현재는 1000개로 묶음.
1024개씩 표기는 kiB, MiB, GiB..

2) 워드(word)
CPU가 한 번에 처리할 수 있는 정보 크기의 단위

  • 하프 워드(half word): 워드의 절반 크기
  • 풀 워드(full word): 워드 크기
  • 더블 워드(double word): 워드의 2배 크기

1-2. 이진법(binary)

0과 1로 숫자를 표현하는 방법이다. 숫자가 1을 넘어가면 시점에 자리를 올린다.
ex) 2 = 10(2)
우리는 9에서 자리를 넘기는 십진법을 사용 중이다. ex) 9+1 -> 10
이진수 8의 경우 1000인데 이대로면 1000이 천인지 이진수로 표현한 8인지를 알 수 없으므로 다음과 같이 표기한다.

  • 1000(2)
  • 0b1000

1) 2의 보수
0과 1로 음수를 표현하는 방법이다.

  • 어떤 수를 그보다 큰 2^n에서 뺀 값
    ex) 5=101(2)의 보수 -> 1000(2) - 101(2) = 11(2)
    그러나 이걸 더 쉽게 구하는 방법이 있다. 바로 0과1을 뒤집고 1을 더하면 된다.
  • 0과1을 뒤집고 1을 더함
    ex) 5=101(2)의 보수 -> 010 + 1 -> 11(2)

근데 이렇게 보수를 표현할 때 11(2)가 -101(2)을 표기하기 위한 건지 그냥 11(2)인지 알 방법이 없다.
이런 상황에서 컴퓨터는 이를 구분하기 위해 플래그가 존재한다.

2) 플래그(flag)
CPU 내부존재하는 특별한 레지스터이다. 이 플래그를 통해 현재 값이 양수인지 음수인지를 파악한다. 그래서 모든 숫자는 값을 전달할 때 플래그가 따로 붙어있다.

1-3. 십육진법

이진법으로 표현하다 면 값이 조금만 커져도 숫자의 길이가 너무 길어진다.
그래서 이 문제를 해결하기 위해 십육진법을 사용한다.
ex) 십진수 32 == 100000(2) == 20(16)
16진수의 표기법도 다음과 같다

  • 20(16)
  • 0x20

십육진수의 장점은 이진수와 서로 변환하기가 쉽다는 점이다.

  • 16진수 -> 2진수
    16진수의 각 자리를 2진수의 4bit라고 생각하고 변환하면 된다.
    ex) 5ABC
    5 = 0101
    A = 1010
    B = 1011
    C = 1100
    5ABC(16) -> 0101101010111100(2)

  • 2진수 -> 16진수
    2진수 4자리를 묶어 16진수로 표현하면 된다.
    ex) 01101101(2)
    0110 = 6
    1101 = D
    01101101(2) = 6D

2. 0과1로 문자를 표현하기

앞서 말했듯 컴퓨터는 0과1로만 정보를 인지하기 때문에 문자도 0과1로만 이해한다.
이 0과1로 문자를 이해하기 위해 3가지 유형을 알아야 한다.

  • 문자 집합(character set)
    컴퓨터가 이해할 수 있는 문자의 모음
  • 인코딩(Incoding)
    코드화하는 과정, 문자를 0과1로 변환
  • 디코딩(decoding)
    코드를 해석하는 과정, 0과1을 문자로 변환

2-1. 아스키 코드

초창기 문자 집합 중 하나. 알파벳, 아라비아 숫자, 일부 특수 문자 및 제어 문자
7비트로 하나의 문자를 표현(8비트인데 1비트는 오류 검출을 위한 패리티 비트를 사용)

  • A는 65로 인코딩, a는 97로 인코딩 등

아스키코드는 7비트로 하나의 문자를 표현하기에 다양한 문자를 표현하기가 어려움(128개를 못 넘어감)
그렇기 때문에 다른 언어들의 인코딩 방식이 필요한 상황

한글 인코딩

  • 완성형 vs 조합형
    한글은 영어와 다르게 초성, 중성, 종성의 조합으로 이루어졌다.
    그렇기에 모든 글자를 전부 담는 완성형과 조합해서 사용하는 조합형이 존재한다.
    1) 완성형
    모든 글자에 대해 고유한 코드를 부여하는 방식이다.
    ex) 한글 : 한(11101110), 글(10111011)

    2) 조합형
    초성과 중성 종성에 대해 각각 고유한 코드를 부여하고 조합하는 방식이다.
    ex) 한 : ㅎ(1111) + ㅏ(1001) + ㄴ(1000 0010)

2-2. EUC-KR

완성형 인코딩 방식으로 글자 하나당 2바이트 크기의 코드를 부여
ex) b0a0 ~ b0af : 가 각 간 갇 갈 갉 갊 감 갑 값 갓 갔 강 갖 갗
이런 식으로 2바이트(16진수로 4자리)로 완성된 글자를 코드로 저장

EUC-KR은 2300여 개의 한글 표현이 가능하나 여전히 모든 한글을 표현하기엔 부족하다.
뷃, 뙠, 휔같은 문자들은 표현이 안 됨

또한 이 경우에는 다국어를 지원할 때 문제가 생긴다. 나라별로 각각 완성형 인코딩을 사용하는 경우, 같은 바이트 값의 경우 무엇을 사용했는지 파악하기가 어렵다.

그래서 모든 언어, 특수문자까지 통일된 문자 집합을 사용하는 유니코드가 등장한다.

2.3. 유니코드

전 세계 모든 문자를 하나의 통일된 문자 집합으로 정의한 국제 표준이다.
기존에 각각 나라별로 독립적인 인코딩 방식(EUC-KR, Shift-JIS, Big5 등)을 하나로 통일함.
유니코드의 인코딩 방식을 utf-8, utf-16 등으로 표현한다.

  • utf-8 인코딩
    UTF(Unicode Transformation Format) == 유니코드 인코딩 방법
    가변길이 인코딩 : 인코딩 결과가 1~4바이트
    -> 인코딩 결과는 유니코드에 부여된 값에 따라 바이트가 달라짐

결국 유니코드는 값을 인코딩할 때 필요한 바이트 수를 문자 값에 따라 다르게 정의하는게 포인트이다.
ex)
1) 'A'

  • 유니코드 값 : 0x41(65)
  • ASCII 범위에 들어감 → 1byte
  • UTF-8인코딩 : 01000001 = 0x41 이므로 ASCII로 인코딩(= 1byte 인코딩)

2) '가'

  • 유니코드 값: 0xAC00(44032)
  • 범위상 3byte 필요
  • UTF-8 인코딩 결과: 1110xxxx 10xxxxxx 10xxxxxx의 규칙을 따름
    실제 인코딩: EA B0 80 (3바이트)

3. 명령어

1. 소스 코드와 명령어

컴퓨터는 우리가 작성한 코드를 바로 이해하긴 어렵다.
그래서 코딩한 내용을 컴퓨터가 이해할 수 있도록 고급 언어에서 저급 언어로 바꿔야 한다.

  • 고급 언어 : 개발자가 이해하기 쉽게 만든 언어
  • 저급 언어 : 컴퓨터가 이해하고 실행하는 언어

1-1. 저급 언어

코딩을 하다 보면 한 번쯤은 들어봤던 단어일 것이다. 저급 언어는 컴퓨터가 이해할 수 있는 명령어로 바꾸는 작업이다.
저급 언어에는 기계어와 어셈블리어가 존재한다.

기계어
0과 1로 이루어진 명령어로 저급 언어이다. 16진수로 표현하는 경우도 존재한다.

어셈블리어
0과 1로 이루어진 기계어를 읽기 편한 형태로 변환한 저급 언어이다.
ex) 0101 0101(기계어) -> push rbp(어셈블리어)

1-2. 고급 언어

우리가 직접 코드를 작성하고 실행하는 언어가 바로 고급 언어이다.
고급 언어는 저급 언어로 변환하는 방법이 컴파일과 인터프리터 2가지 방식이 존재한다.

컴파일 언어
소스코드가 컴파일러를 통해 목적 코드를 생성한다.
소스 코드: 고급 언어로 작성한 코드
컴파일: 컴파일러를 통해 소스 코드를 저급 언어로 바꾸는 과정
목적 코드: 컴파일 결과로 생성된 저급 언어

인터프리터 언어
인터프리터에 의해 한 줄씩 실행한다. 그래서 컴파일 언어와 다르게 소스 코드 전체가 저급 언어로 변환되기까지 기다릴 필요가 없다.
따라서 인터프리터 중 오류가 발생하면 오류 발생 지점 전까지 코드를 실행한다.

그렇다고 모든 언어가 컴파일과 인터프리터로 완전히 분리되는 것은 아니고, 고급 언어를 저급 언어로 바꾸는 2가지 방식이며 각각 변환하는 과정이 다르다고 알면 좋다.

2. 명령어 구조

저급 언어는 결국 명령어들로 이루어져 있는데, 이 명령어가 각각 어떻게 생겼고 어떻게 동작하는지를 알아보려고 한다.
명령을 일상적인 대화로 풀어본다면 이런 식으로 요청할 수 있다.
"용주야, 방 좀 치워라"
"승우야, 차로 집에 데려다줘"
"석훈아, 일요일에 카페에서 봐"
일상에서 이런 식으로 요청을 할 수 있는데 컴퓨터도 무엇을 대상으로, 무엇을 실행해라. 라는 구조를 가진다. 더 자세하게 표현하자면 컴퓨터는 이런 방식이다.

  • 수행해라, 이것을

이게 컴퓨터가 명령어를 수행하는 방식이다. 예를 들어 표현하자면,
ex) 더해라, 100과 120을 / 빼라, 20번 주소와 30번 주소를 등
명령어는 이런 형태로 볼 수 있는데 여기서 더해라, 빼라를 연산 코드라 하고 연산에 사용될 데이터 및 주소를 오퍼랜드라고 부르며 이로 구성되어 있다.

2.1 오퍼랜드

연산에 사용될 데이터 혹은 데이터가 저장된 위치이다. 그리고 연산에 사용될 데이터가 저장된 위치 이를 주소 필드라고 부른다. 그래서 오퍼랜드를 주소 필드라고 부르기도 한다.
여기서 명령어를 수행할 때 오퍼랜드가 없을 수도 있고 여러 개 있을 수도 있다.

2.2 연산 코드

수행할 연산을 의미한다. 연산 코드는 cpu마다 다른데 크게 4가지로 구성되어 있다.

  • 데이터 전송
  • 산술/논리 연산
  • 제어 흐름 변경
  • 입출력 제어

데이터 전송
데이터를 옮긴다(MOVE)
메모리에 저장한다(STORE)
메모리에서 데이터를 가져와라(LOAD, FETCH)
스택에 저장해라(PUSH)
최상단 데이터를 가져와라(POP)

산술/논리 연산
사칙연산(ADD/SUBTRACT/MULTIPLY/DIVIDE)
오퍼랜드에 1을 더해라/뺴라(INCREMENT/DECREMENT)
논리연산(AND/OR/NOT)
비교해라(COMPARE)

제어 흐름 변경
특정 주소로 실행 순서를 옮겨라(JUMP)
조건에 부합할 때 실행 순서를 옮겨라(CONDITIONAL JUMP)
프로그램 실행을 멈춰라(HALT)
되돌아올 주소를 저장한 채 특정 주소로 실행 순서를 옮겨라(CALL)
CALL을 호출할 때 저장했던 주소로 돌아가라(RETURN)
// call과 return은 함수와 동일하다고 이해하면 편함

입출력 제어
데이터를 읽어라(READ, INPUT)
데이터를 써라(WRITE, OUTPUT)
시작해라(START IO)
상태를 확인해라(TEST IO)

명령어 주소 지정 방식

오퍼랜드에서 데이터만 바로 저장하여 쓰면 좋겠지만 그게 안 되는 경우가 많다.
예를 들면 오퍼랜드의 개수가 늘어날 때마다 오퍼랜드에서 표현할 수 있는 데이터 크기가 줄어들어 10000같은 숫자를 넣을 수 없게 된다.
그렇기 때문에 데이터를 직접 저장하지 않고 데이터가 저장된 메모리 위치의 주소를 저장할 수 있다.
이때, 연산에 실제로 사용될 데이터의 메모리 주소를 유효 주소라고 한다.
그리고 이러한 유효 주소를 찾는 방식이 바로 명령어 주소 지정 방식이라고 한다.

즉시 주소 지정 방식(immediate addressing mode)
연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시한다.
따라서 이는 따로 주소를 저장하지 않기에 유효 주소가 존재하지 않는다.
사용할 데이터 크기가 연산 코드만큼 줄어들지만, 빠르다.

직접 주소 지정 방식(direct addressing mode)
오퍼랜드 필드에 유효 주소 직접적으로 명시
이것 또한 유효 주소를 표현할 수 있는 크기가 연산 코드만큼 줄어든다.

간접 주소 지정 방식(indirect addressing mode)
오퍼랜드 필드에 유효 주소의 주소를 명시
주소의 주소를 찾는 방식이기 때문에 속도가 느림

레지스터 주소 지정 방식(register addressing mode)
연산에 사용할 데이터가 저장된 레스지터 명시
메모리보다 레지스터에 접근하는 게 더 빠름

3. C언어 컴파일 과정

c언어에서 작성한 소스코드를 실행파일로 만들 때 과정은 다음과 같다.

3-1. 전처리기(Preprocessor)

전처리기는 컴파일 이전 단계에서 소스 코드를 처리하여 컴파일러가 이해할 수 있는 형태로 코드를 확장 및 정리하는 과정이다.
즉, 본격적인 컴파일 전에 필요한 작업을 미리 수행해 주는 역할을 한다.

예를 들어 printf()와 scanf() 같은 함수는 실제로 stdio.h 헤더 파일에 선언되어 있다.
하지만 직접 정의한 함수가 아니기에 컴파일러는 이 함수를 이해할 수 없다.
그래서 전처리기는 #include <stdio.h>를 보고 해당 헤더 파일의 내용을 소스 코드에 그대로 포함시켜준다.
이 과정을 통해 printf()와 scanf()가 어떤 함수인지 인식할 수 있게 된다.
단, 소스 코드에 함수를 정의하는 게 아니라 존재한다는 여부만 알림(실제 해당 함수의 구현은 링커가 연결해 줌)

  • 본격적으로 컴파일전에 처리할 작업들
  • 외부에 선언한 다양한 소스 코드 및 라이브러리 (ex- #include)
  • 프로그래밍 편의를 위한 작성된 매크로 변환 (ex- #define)
  • 컴파일 영역 명시 (ex- #if)

3-2. 컴파일러(Complier)

전처리가 완료되어도 여전히 c언어로 이루어진 소스 코드와 다를 게 없다.
그래서 컴파일러가 컴파일을 통해 컴퓨터가 이해하기 쉬운 저급 언어로 바꾸는 단계이다.
즉, 전처리된 코드를 받아 어셈블리어로 변환하는 단계이다.

소스 코드가 .s라는 어셈블리 코드 파일로 변환되며 아직 기계어는 아니지만 하드웨어에 가까운 저수준 언어가 된다.

3-3. 어셈블러(Assembler)

어셈블러는 어셈블리 코드를 실제 CPU가 실행할 수 있는 기계어로 번역한다.
그 결과 생성되는 것이 바로 목적 파일이다.

그러나 목적 파일은 완전한 실행 파일이 아니다.
이 파일은 기계어로 되어 있으나, 외부 함수나 라이브러리에 대한 연결이 되어 있지 않아 해당 정보를 사용할 수 없는 상태이다.
그래서 외부의 정보를 연결해 주는 것이 바로 링커이다.

3-4. 링커(linker)

링커는 여러 개의 목적 파일(.o)과 라이브러리(.lib)를 연결하여 하나의 실행 파일(.exe)을 생성하는 역할을 수행한다.
예시로 작성한 소스 코드가 main.c, math.c, util.c로 나뉘어 있다면, 각 파일은 별도의 목적 파일로 변환되지만 이 목적 파일들을 하나로 묶어야 프로그램이 실행될 수 있다. 링커는 이런 요소들을 합치는 역할이다.

  • 목적 파일들을 하나로 병합
  • 외부 함수나 변수의 참조를 해결(ex- printf()는 실제 라이브러리의 함수로 연결)
  • 최종 실행 가능한 실행 파일 생성

4. CPU 작동원리

1. ALU와 제어장치

cpu의 구성요소에 연산 장치인 ALU와 제어 신호를 발생시키고 명령어를 해석하는 장치인 제어 장치의 동작 원리를 파악한다.

1-1. ALU

ALU는 산술 연산(덧셈, 뺄셈 등)과 논리 연산(AND, OR, NOT 등)을 수행하는 장치이다.
ALU는 연산에 필요한 피연산자를 레지스터나 메모리로부터 받아오고, 제어 장치로부터 받은 제어 신호에 따라 연산을 수행한다.
연산이 완료되면 결과값은 다시 레지스터에 저장되며, 연산 결과에 따라 여러 상태 플래그(Flag)가 설정된다.

  • 부호 플래그: 결과의 부호가 음수면 1, 양수면 0
  • 제로 플래그: 결과가 0이면 1, 아니면 0
  • 캐리 플래그: 덧셈 시 자리올림이 발생하거나 뺄셈 시 자리내림이 발생하면 1, 아니면 0
  • 오버플로우 플래그: 정수 범위를 벗어난 연산이 발생하면 1, 아니면 0
  • 인터럽트 플래그: 인터럽트 허용 여부를 나타냄. 1이면 허용, 0이면 차단
  • 슈퍼바이저 플래그: 현재 CPU 모드가 커널 모드인지 사용자 모드인지 나타냄. 1이면 커널 모드, 0이면 사용자 모드

1-2. 제어장치

제어 장치는 CPU 내부의 동작을 제어하고 조율하는 역할을 한다. 명령어를 해석하여 ALU, 레지스터, 메모리 등에 적절한 제어 신호를 보내고, 프로그램 실행의 흐름을 결정한다.

  • 클럭(Clock): 컴퓨터의 모든 부품을 일사불란하게 움직일 수 있게 하는 시간 단위
    컴퓨터 전체 부품의 동작을 동기화하는 시간 신호로, CPU의 모든 동작은 클럭 신호를 기준으로 이루어진다. 클럭 주파수가 높을수록 연산 속도도 빨라진다.

  • 명령어 해석기(Instruction Decoder): 주기억장치에서 가져온 명령어를 해석하여 어떤 연산을 수행할지 결정한다.

  • 플래그 상태 감지기: 연산 결과로 설정된 플래그를 확인하여 이후의 명령 실행 흐름(예: 조건 분기)을 제어한다.

제어 장치는 프로그램의 각 명령어를 순차적으로 해석하고 실행하기 위한 제어 흐름을 생성하며, ALU나 레지스터, 메모리 등과 협력하여 명령 실행을 완성한다.

2. 레지스터(Register)

레지스터는 CPU내부의 위치한 매우 빠른 임시 저장 장치로 명령어 실행 중 필요한 데이터를 일시적으로 저장하는데 사용된다. ALU나 제어 장치보다도 더 빈번하게 접근되며, 여러 종류의 특수 목적 레지스터와 범용 레지스터로 구성된다.

레지스터 종류

  • 프로그램 카운터(PC, Program Counter): 다음에 실행할 명령어의 메모리 주소를 저장.
  • 명령어 레지스터(IR, Instruction Register): 현재 실행 중인 명령어를 저장
  • 메모리 주소 레지스터(MAR, Memory Address Register): 접근하고자 하는 메모리 주소를 저장. 주소 버스를 통해 해당 주소를 전달.
  • 메모리 버퍼 레지스터(MBR, Memory Buffer Register): 메모리에서 읽어오거나 메모리에 쓸 데이터를 임시 저장. 데이터 버스를 통해 입출력.
  • 플래그 레지스터(Flag Register): 연산 결과 및 CPU 상태를 나타내는 플래그들을 저장.
  • 범용 레지스터(General Purpose Register): 다양한 연산에 사용되는 임시 저장 공간.
  • 스택 포인터(SP, Stack Pointer): 현재 스택의 최상위(Top)를 가리키는 포인터.
  • 베이스 레지스터(Base Register): 기준 주소(base address)를 저장하여 주소 계산 등에 사용.

2-1. CPU 내부 레지스터 동작방식

메모리 1000~1200번지까지 데이터를 읽어올 때 CPU 내부 레지스터 동작방식은 다음과 같다.

  1. 프로그램 카운터에 1000번지 저장
    CPU는 다음 명령어의 위치를 알아야 하므로, 프로그램 카운터에 1000번지를 저장한다.
  2. 메모리 주소 레지스터(MAR)에 1000 저장
    프로그램 카운터의 값을 MAR로 복사하고, 메모리 접근을 요청한다. 해당 주소의 데이터를 읽기 위해 주소 버스와 제어 신호가 사용된다.
  1. MBR에 데이터(예: 1100(2)) 저장 및 PC 증가
    메모리에서 읽어온 데이터(예: 명령어 코드 1100(2))는 MBR에 저장된다.
    MAR는 초기화되고, 프로그램 카운터는 다음 명령어를 위해 자동으로 증가한다.
  2. 명령어 레지스터에 명령어 저장
    MBR에 저장된 명령어(1100(2))가 명령어 레지스터(IR)로 이동되어 해석 및 실행 준비가 된다.

이 과정을 반복하면서 CPU는 순차적으로 메모리로부터 명령어와 데이터를 읽어 실행하게 된다.

2-2. 스택 주소 지정 방식

스택 주소 지정 방식은 스택 포인터(SP)를 활용하여 데이터를 저장하거나 불러오는 방식이다.
스택 포인터는 항상 스택의 최상단 주소를 가리키며, 데이터가 PUSH되면 감소(하향식 스택의 경우), POP되면 증가한다.
예를 들어, 스택 포인터가 4번지를 가리킨다는 것은 스택의 최상단이 4번지에 위치하고 있음을 의미한다. 함수 호출 시 지역 변수나 리턴 주소를 저장하는 데 자주 사용된다.

2-3. 변위 주소 지정 방식

오퍼랜드 필드의 값(변위)과 특정 레지스터 값을 더하여 유효 주소를 얻는 방법
레지스터의 저장된 값과 오퍼랜드 필드의 값을 더하여 해당 위치에 값을 저장한다.

특정 레지스터 종류는 크게 프로그램 카운터와 베이스 레지스터로 구성됨

  • 상대 주소 지정 방식: 오퍼랜드 필드의 값과 프로그램 카운터의 값을 더하여 유효 주소 얻기
  • 베이스 레지스터 주소 지정 방식: 오퍼랜드 필드 값과 베이스 레지스터 값을 더하여 유효 주소 얻기
    베이스 주소가 정해져있고 오퍼랜드 값만큼 더하여 해당 주소에 값을 저장




Reference
저자: 강민철
제목: 『혼자 공부하는 컴퓨터 구조+운영체제』
출판지: 한빛미디어
강의 링크: https://www.youtube.com/watch?v=kFWP6sFKyp0&t=10293s

0개의 댓글