본문 바로가기

IT개발/컴퓨터구조

컴퓨터 구조에 대한 설명(2-1)

목표 : 컴퓨터 구조 전문가가 되어 컴퓨터를 구성하는 요소를 하나씩 디자인

 

 

지금 시간은 10시..

오늘은 시스템 프로그래머 입장에서 좀 더 컴퓨터 구조에 대해  근본적인 이해를 해보려 한다.

 

즉, 잠시 컴퓨터 구조 전문가가 되어 컴퓨터를 구성하는 요소를 하나씩 디자인해 나가는 것이다.

 

좀 더 구체적으로 무엇을 디자인 할꺼냐고? 물론 CPU다.

 

우리는 1장을 통해 CPU를 구성하는 기본요소는 다음과 같음을 알 수 있었다.

 

- ALU

- 컨트롤 유닛

- 레지스터

 

우리는 이중에서 레지스터에 초점을 맞추려 한다.

 

그 이유는 시스템 프로그래머 입장에서 CPU를 보는 관점의 대부분이 레지스터에 집되기 때문이다.

 

 

 

 

※ 레지스터 디자인

 

레지스터를 디자인하는데 있어 결정해야 하는 중요한 사항은 다음과 같다.  ( 우리가 결정한 사항은 옆에 표시 ) 

 

----------------------------------------------------------------------------------------------------

1) 레지스터를 몇 비트로 구성할 것인가?     ------> 편의상 16비트로 하자. (64비트는 표현하기 불편하다)

2) 몇 개정도의 레지스터를 구성할 것인가?    -----> 8개로 제한하자

3) 레지스터 각각을 무슨용도로 사용할 것인가? ---> 레지스터 이름은 r0~r7 까지로 정하자

----------------------------------------------------------------------------------------------------

 

 

이것이 레지스터 디자인의 핵심이다.

 

이러한 형태로 구성하면 CPU 내부에는 다음과 같은 구조로 레지스터들이 존재할 것이다.

 

 

 

          Register Set 

----------------------------

r0

----------------------------

r1

----------------------------

r2

----------------------------

r3

----------------------------

r4   ir   (instruction register)

----------------------------

r5   sp (stack pointer)

----------------------------

r6   lr   (link register)

----------------------------

r7   pc (program counter)

-----------------------------

 

cf) 위 레지스터 구조는 ARM 코어를 참조했다. 이는 다른 CPU보다 하드웨어 구성과 명령어 구조가 간단하기 때문이다.

     ARM은 간단한 만큼 전력소비가 아주적다. 그래서 핸드폰에 매우 적합한 코어이다.

 

 

 

 

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

 

이번에는 CPU에게 일을 시키기 위한 명령어 구조 및 명령어 종류를 디자인해보자.

자~ 다시말한다. "레지스터를 디자인 했으니, 이를 바탕으로 명령어를 디자인할 차례다."

 

여기서 주목할 것은 레지스터 - 명령어의 상관관계다.

 

cpu구성형태( 레지스터 구성형태)에 따라서 명령어 구조는 달라진다.

이처럼 cpu가 달라지면, 이에 따른 명령어 구조가 달라지기 때문에, 어셈블리 언어로 구현된 프로그램은

구조가 다른 cpu로 이식이 불가능하다.

 

이제 명령어를 디자인 해보자.

 

우선 명령어를 몇 비트로 구성할 것인지 결정해야 하는데, 16비트 레지스터닌까 명령어의 길이도 16비트로 구성해보자.

 

여기서 중요한 것은 16비트를 어떻게 활용할 것인가 하는것이다.

 

만약 "0000000000000001" -> 뎃셈

       "0000000000000010" -> 뺄셈 이렇게 생각했다면 이것만큼 비효율적인것은 없다.

 

표현가능한 명령어만 65536개가 된다는 것인데, 세상 어떤 cpu도 독립적 명령어수가 3자리를 넘지 않는다.

 

그럼 좀 더 효율적인 방안을 생각해보자. ^^

 

cpu에게 일을 시킬때는 다음과 같은 형태로 일을 시키게 된다.

 

"레지스터 r1에 있는 값과 숫자7을 더해서 레지스터 r2에 저장하라"

 

-> 보다시피, 뎃셈연산을 위해서는 뎃셈대상이 되는 피연산자 둘(r1, 7)에 , 연산결과 저장을 위한 피연산자(r2)가 필요하다.

     이것을 모두 16비트 명령어 하나에 담을수만 있다면 아주 효율적이라 할 수 있다.

 

이런 이에 대한 방안을 고민해보자~

 

"뎃셈", "레지스터r1", "레지스터r2", "숫자7"

 

 

좀 구조를 달리해보면 밑에와 같이 표현도 가능할 것이다.

 

-----------------------------------------------------

예약(2)  연산자(3)  저장소(3)  피연산자1(4)  피연산자2(4)

             ADD           r2               r1                 7

-----------------------------------------------------

 

- 저장소        : 레지스터

- 피연산자1,2 : 레지스터 or 숫자

 

 

* 저장소가 3비트인 이유 : 레지스터 8개닌까 3비트로 충분히 표현이 다 된다.

                                    (또한 일반적인 ALU는 연산결과를 레지스터에 저장하기 때문에 이런 규칙을 따른것이다.)

   

반면 그 뒤에 4비트는 레지스터 정보나 숫자가 올수 있도록 디자인 했다.

 

레지스터 정보가 온다는 말은, 레지스터 안에 저장된 데이터를 참조하겠다는 의미로 해석하면 된다.

 

 

* 연산자에 3비트를 할당했으니, 우리가 만들수 있는 연산자 개수는 총 8개를 넘지 못한다. 그럼 일단 4개정도 결정하자.

(덧셈, 뺄셈, 곱셈, 나눗셈)

 

더불어 어셈블리 프로그래밍을 할 때 사용되는 심볼(Symbol, 어셈블리 명령어) 결정을 하자.

 

 

연산의미 / 심볼 / 2진 코드

-------------------------

덧셈         ADD      001

뺄셈         SUB      010

곱셈         MUL      011

나눗셈      DIV       100

-------------------------

 

그리고 각 레지스터를 나타내는 2진 코드도 다음과 같이 구성해보자.

 

 

 

레지스터 심볼  /  2진코드

-------------------------

      r0             000

      r1             001

      r2             010

      r3             011

      r4,ir          100

      r5 ,sp        101

      r6 ,lr          110

      r7 ,pc        111

-------------------------

 

이제는 피연산자 2개를 표현해 보자.

 

두개의 피연산자는 숫자가 될수도 있고, 레지스터가 될수도 있다. 즉, 다음과 같은 연산이 가능하게 된다.

 

r2 = r1 + r3

r2 = r1 + 4

r2 = 5 + r1

r2 = 3 + 5

 

이제는 뭘 생각해봐야 할까? 물론 저장된 데이터가 숫자를 표현하는 건지, 레지스터 정보를 표현하는 것인지 구분을 할수 있어야 한다.

예를 들어 0001이 들어있다면 이게 r1을 의미하는지 숫자1을 의미하는지 알 수가 없다.

 

이 문제를 해결하기 위해 또 하나 비트를 희생시켜보자.

( 4개 비트중에 최상위 비트가 1이면 레지스터 정보를 담는거고, 0이면 숫자정보라고 가정해보자 )

 

즉, 1001 -> r1정보

     0001 -> 숫자 1을 의미한다.

 

우리가 구성한 명령어 구조는 한 가지 제약이 있다.

 바로 피연산자로 표현할 수 있는 숫자가 여덟게 밖에 안된다는 것이다.(3비트)

 

 이 해결책은 좀 쉬고, 다시 알아보자.

 

 자 지금까지 내용을 어제 배운 것에 적용시켜 보자.

 

 

CPU(Central Processing Unit)

------------------------------------------------------------

                                                                                                                             ---  Assemble  [ ADD, r2, r1, 7 ]

ALU(Arithmetic Logic Unit)      ----  레지스터 (Register Set)                                          

                                        |                  (ir에 저장)                                             ↓    메모리 로드

                (Execution)     |                                                             -----------------------------

컨트롤 유닛(Control Unit)    <-|       버스 인터페이스(Bus Interface)               메인 메모리(Main Memory)

                   (Decode)                                                                                       명령어 A                       

------------------------------------------------------------              -----------------------------

                      ↑                                                                                                    

                      ↓                              ↑                                                                     ↓   (Fetch)

 =======   입출력 버스 (I/O BUS) ==================================================================

       ↑                 ↑                      ↑                         ↑

       ↓                 ↓                      ↓                         ↓

    키보드          모니터           네트워크카드           하드디스크

 

 

 

참고) 우리가 구성하는 명령어 형태에 따라 컨트롤 유닛의 구조가 결정된다. 생각해보자. 컨트롤 유닛의 역할은 명령어 해석이다.

         따라서 명령어 구성 및 해석방법을 정확히 알고 있어야만 해석이 가능하다

         = 명령어 형태에 따라 컨트롤 유닛의 논리회로가 디자인

 

 

참고) 왜 첫번째 피연산자 위치에는 레지스터 이름이 와야 하는가? (제약사항)

 

        -> 이런 제약사항은 cpu의 종합적인 측면(성능,비용 등등)이 고려되는 가운데서 등장하게 된다. 따라서 우리는 이런 제약사항을

             반드시 지켜야 한다.

 

 

 

참고) RISC vs CISC

 

CISC - Complex Instruction Set Computer :

           말그대로 복잡한 명령어 체계를 가진 컴퓨터 의미고, 인텔 16비트 cpu까지는 CISC 구조였다.

           하지만 복잡한 구조는 성능향상에 제한이 따른다.

           따라서 보다 높은 성능의 CPU디자인을 위해 보다 단순한 CPU구조가 필요하다.

 

RISC - 그래서 나온게 RISC이다.

          CISC구조 CPU가 지니는 전체 명령어중 실제 주로 사용하는 명령어는 10%정도라는데서 착안된 구조

          결국 명령어 수를 대폭줄이고, 명령어 길이를 일정하게 디자인해서 RISC을 만들었다.

          인텔의 32, 64 비트 CPU 뿐만 아니라 근래에 임베디드 환경에서 사용되는 CPU가 RISC구조다.

 

 

-> 그럼 왜 어떤이유로 높은 성능을 내는걸까? 초당 클럭수를 높이는 것도 선능향상을 위한 일이지만,

     이보다 중요한것은 클럭당 처리할 수 있는 명령어의 개수다. RISC은 동일한 명령어 길이와 명령어 처리 과정이 일정하기 때문에

     클럭당 둘 이상의 명령어 처리가 가능하다. (Pipelining 기법)

 

     바로 이점이 성능향상에 있어 RISC 구조가 지니는 가장 큰 장점이 된다.