✏️ 컴퓨터 구조의 접근 방법

💻 컴퓨터(CPU)를 디자인하자

GPU도 일종의 CPU.
CPU 연산의 대상이 범용적이라면 GPU의 연산 대상은 그래픽에 국한되어 있다는 점이 차이점.

  • 프로그래머 관점

    • 레지스터와 명령어의 디자인
    • 컴퓨터 구조를 잘 아는 프로그래머도 컴퓨터 디자인에 참여
  • 레지스터 디자인의 핵심

    • 레지스터는 몇 비트로 구성할 것인가?

      • N비트 시스템에서는 레지스터도 N비트
      • 레지스터는 저장소이기 때문에 N비트 명령어를 저장할 수 있다.
      • 여기서는 16비트. 따라서 명령어도 16비트.
    • 레지스터를 몇 개로 구성할 것인가?

      • 레지스터의 수는 많으면 많을수록 좋다.
      • 여기서는 8개.
    • 각 레지스터를 무슨 용도로 사용할 것인가?

      • 레지스터는 특정 용도를 가진 저장소
      • 용도를 정해주면 명령어가 단순해지고 속도가 빨라진다.

    위 4개는 범용(연산) 레지스터, 아래 4개는 전용 레지스터

💻 명령어 구조 및 명령어 디자인

  • 명령어 디자인의 제한
    • 사칙연산의 피연산자는 숫자 or 레지스터
    • 연산 결과는 레지스터에 저장
    • 즉 레지스터를 통해 모든 연산을 진행할 것.

레지스터와 명령어의 비트 크기가 같아야 CPU로 명령어가 fetch될 때 하나의 명령어가 하나의 레지스터에 저장될 수 있다.

  • 사칙연산 명령어 구성
    ALU -> 명령어를 해석하는 장치
    명령어가 디자인되어야 ALU가 명령어를 어떻게 해석해야하는지 알 수 있다. 이는 CPU 디자인과 함께 명령어 디자인이 필요한 이유.

피연산자로 레지스터와 숫자가 올 수 있다면, 001이 올 때 숫자를 의미하는지 2진 코드를 의미하는지 알 수 없다. 따라서 피연산자의 첫번째 비트는 이를 구분하는데 사용할 것.
명령어를 디자인하는데 허용하는 범위가 넓을 수록 손해보는 비트가 늘어난다. 이것이 명령어 범위에 제한을 두는 이유. 많은 비트를 요구할수록 명령어가 복잡해진다.
4개의 비트는 숫자를 표현하기에 부족하다.

RISK vs CISK

  • RISK
    • 명령어 구조가 단순한 CPU
    • 오늘날 대부분 CPU의 형태
  • CISK
    • 명령어 구조가 복잡한 CPU
    • 다양한 형태로 명령어를 조합할 수 있다.

하나의 명령어를 실행하는 과정 => Fetch - Decode - Execution
각 과정에서 한 클럭씩 소요
각 로직이 별개이기 때문에 동시에 실행되더라도 문제가 되지 않는다.

  • RISK의 특징
    • RISK의 경우 명령어를 단순하게 디자인해서 모든 명령어가 F D E의 과정을 거치는 것이 특징. CISK의 경우 이보다 복잡하다.
  • 장점
    • RISk가 명령어 5개를 처리할 경우, 각 로직은 별개이기 때문에 첫번째 명령어가 Decode될 때 다른 명령어를 Fetch할 수 있고, 첫번째 명령어가 Execution될 때 Decode할 수 있다.
    • 따라서 N개의 명령어를 처리하는데 필요한 클럭 수는 N + 2개

✏️ LOAD & STORE 명령어 디자인

  • LOAD & STORE 명령어의 필요성
    • 모든 CPU의 결과는 레지스터를 통해서 빠져나간다.
    • 데이터 입출력 관점에서 레지스터는 임시 저장소.
    • 성능 향상을 위해 RISK 구조를 택했기 때문에 결과를 바로 메인 메모리에 저장할 수 없고, 레지스터를 거쳐야 한다.
    • 또한, 피연산자는 레지스터 or 숫자만 받을 수 있고 메모리 주소를 직접적으로 받을 수 없다.
    • 따라서 메모리에 있는 정보를 레지스터로 불러들이기 위한 LOAD 명령어와, 연산 결과를 메모리에 저장하기 위한 STORE 명령어가 필요하다.

아래 연산에서 a, b, c는 모두 메모리에 있는 값이기 때문에, 먼저 a와 b를 레지스터에 불러와야 한다.

  • LOAD
    메인 메모리 0x20번지에 있는 값을 r1에 저장해라.

  • STORE

    r1에 있는 데이터를 메인 메모리 0x20에 저장해라.

  • 덧셈 연산

    0x10과 0x20은 메모리 주소이기 때문에 먼저 레지스터로 LOAD하는 과정이 필요하다. 피연산자로는 레지스터 or 숫자만 올 수 있도록 설계했기 때문이다. 따라서 세번째 명령어에서 피연산자인 레지스터 r3은 LOAD 할 필요가 없다.
    위 과정은 실제 CPU 내부 연산과 같다.

✏️ Direct모드와 Indirect모드

  • 명령어 구성의 또 다른 문제점
    • 명령어 비트 수가 제한되어 있기 때문에 피연산자 표현에 한계가 있다.
    • 아래 사진에서 20은 0x0100번지에 있기 때문에 현재 참조 불가.

💻 Direct모드

메모리의 주소 값을 직접 지정해서 가져오는 것.
ex) 0x10번지에 저장되어 있는 10을 가져온다.

💻 Indirect모드

메모리의 주소 값을 거쳐서 그 곳에 저장되어 있는 값을 가져오는 것.
ex) 0x10번지에 저장되어 있는 주소 값 0x30번지에 가서, 10을 가져온다.

  • 문제 해결
    현재 명령어로 0x0100에 접근하는 법
    • 4 * 4 = 16, 즉 0x0010을 r0에 저장
    • 4 * 4 = 16, 즉 0x0010을 r1에 저장
    • 16 * 16 = 256, 즉 0x0100을 r3에 저장
    • r3에 저장된 0x0100을 메모리 0x0030번지에 저장
    • 0x0030번지에 저장된 주소 값 0x0100을 참조해 r2로 로드. 0x0100에 저장되어 있는 값은 20 => Indirect모드

0개의 댓글