틀린 그림 찾기? 프로세서 DEEP DIVE

Bor·2021년 10월 13일
0

컴퓨터구조

목록 보기
5/15
post-thumbnail

🌌단일 데이터 패스 만들기🌌


이제까지 각각의 명령어 종류에 필요한 데이터 패스 구성 요소에 대해 알아봤다. (엑조디아의 구성품을 모으는 것처럼) 이제 🏇데이터패스 구성요소들을 하나로 묶고 여기에 제어를 첨가함으로써 구현을 완성하고자 한다. 가장 간단한 데이터패스는 모든 명령어를 한 클럭 사이클에 실행하도록 시도하는 것이다.

이는 어느 데이터패스 자원도 명령어당 두 번 이상 사용될 수 없음을 의미한다. 따라서 두 번 이상 사용할 필요가 있는 구성 요소는 필요한 만큼 여러개 두어야 한다. 그러므로 📊데이터 메모리와는 별도로 🔀명령어 메모리가 필요한 것이다.

두 개의 다른 명령어 종류들이 데이터패스 구성요소를 공유하기 위해서는 그 구성 요소의 입력에 여러 개의 연결을 허용해야 하며, 멀티 플렉서와 제어 신호를 사용해서 그 입력들 중 하나를 선택해야 한다.


데이터패스 구축

산술/논리 (R형식) 명령어 데이터패스와 메모리 명령어 데이터패스는 매우 비슷하나 다음과 같은 점이 다르다.

  • 🧮산술/논리 연산 명령어는 ALU를 사용하는데, 입력은 두 레지스터에서부터 온다. 메모리 명령어 역시 주소를 계산하기 위해 ALU를 사용하지만, ALU의 두 번째 입력은 명령어의 16비트 변위 필드를 부호확장한 값이다.

  • 🗽목적지 레지스터에 저장되는 값은 ALU에서 (R명령어 형식인 경우)오거나 메모리에서 (적재 명령어인 경우) 온다.

메모리 참조 명령어와 산술/논리 연산 명령어를 실행하는 🏇 데이터 패스를 만들되 레지스터 파일 하나와 ALU 하나를 사용하여 두 종류의 명령어를 처리해보자.

레지스터 파일 하나와 ALU 하나만을 사용하는 데이터 패스를 만들기 위해서는 두 번째 ALU입력에 두 종류의 다른 근원지를, 그리고 레지스터에 저장할 데이터 입력에도 🗽 두 개의 다른 근원지를 연결할 수 있어야 한다. 🗽

따라서 ALU입력에 멀티플렉서 하나, 레지스터 파일의 데이터 입력에 멀티 플렉서 하나를 설치해야 한다. 아래 그림에 합쳐진 🏇 데이터패스를 보였다.

이제 명령어 인출을위한 🏇데이터 패스, 🧮R형식 명령어와 메모리 명령어를 위한 데이터패스, 분기 명령어를 위한 데이터 패스 를 하나로 합쳐서 엑.조.디.아 MIPS 구조를 위한 단순화된 데이터 패스를 만들 수 있다.

이는 이렇게 분리된 조각들을 합쳐서 만든 데이터 패스를 보여주고 있다. 준기 명령어는 주 ALU를 레지스터 피연산자 비교에 사용하므로 분기 목적지 주소 계산을 위해서는 ➕덧셈기가 있어야 한다. (추가된 것을 유심히 보자) 또한 PC에 들어갈 값으로 순차적인 다음 명령어 주소(PC+4)와 분기 목적지 주소 중 하나를 선택하기 위해 또 다른 멀티플렉서가 필요하다.

🔥 이제 기본 명령어들을 한 클럭 사이클에 실행할 수 있다! 🔥 

이와 같은 단순화한 데이터 패스를 완성했으니 이제는 🎮 제어 유닛 🎮을 덧붙여보자.제어 유닛은 필요한 입력을 받아들여 각 상태소자의 쓰기 신호, 각 멀티플렉서의 선택 신호, 그리고 ALU 제어 신호를 만들어 내야 한다. ALU 제어 유닛은 여러가지 면에서 다르기 때문에 이것을 먼저 설계하고 나머지는 그 다음에 하는 것이 바람직.


4.4 🔨 단순한 구현 🔨

이제 멋지게 카드를 내보자! MIPS를 간단하게 구현해보자. 물론 간단해보이지만 들어가면 전혀 간단하지 않은데 (자네가,,, 수업중에 정줄을 놨던 것은 말이 되고...?) 앞선 장에서 살펴본 것에 LW, SW, beq, 산술/논리 명령어인 add, sub, and, or, slt 명령어 등을 포함한다.

ALU 제어

MIPS ALU는 제어 입력 4개를 사용하는 다음 6개 조합을 정의하고 있다.

ALU는 명령어 종류에 따라 첫 5가지 기능 중 하나를 수행한다.

✔️ 워드 적재, 워드 저장 명령어인 경우 메모리 주소를 계산하기 위한 덧셈용으로 ALU를 사용한다.
✔️ R 형식 명령어의 경우에는 명령어 하위 6비트의 기능 필드 값에 따라서 5가지 연산 (AND OR sub add slt) 중 하나를 수행한다.
✔️ 같을시 분기 명령어의 경우에 ALU는 뺄셈을 수행하게 된다.

✔️ 명령어의 기능 필드와 2비트 제어 필드(ALUOp라 불림)를 입력으로 갖는 조그만 제어 유닛을 만들어서 4비트 ALU 제어 입력을 발생시킬 수 있다. ALUOp가 표시해야할 연산은 적재와 저장의 경우에는 덧셈(00)

✔️ beq의 경우에는 뺄셈(01), 산술/논리연산의 경우엔느 기능 필드에서 나타나는 연산(10)이 된다. ALU 제어 유닛의 출력은 4비트 신호인데 이는 조합 중 하나를 남들어내면서 ALU를 직접 제어한다.


주제어 유닛이 ALUOp 비트를 생성하고 ALU 제어 유닛은 이것을 입력으로 받아서 ALU를 제어하는 실제 신호를 만들어 내는 이런 디코딩은 많이 사용된다. 다단계 제어를 사용하면 주제어 유닛의 크기를 줄일 수 있다. 또 여러 개의 작은 🎮제어 유닛🎮을 사용하는 것은 유닛의 속도를 증가시킬 수도 있다. 👍👍

2비트 ALUOp 필드와 6비트 기능 필드를 4비트의 ALU 연산 제어 비트로 사상 시키는 방법은 여러가지가 있다. 기능 필드가 가질 수 있는 값 64개 중에서 몇 개만이 사용되고 그것도 ALUOp비트가 10(2)일때만 사용되기 때문에, 가능한 값들 중 일부만 사용해 ALU 제어 비트를 만들어내는 조그만 논리회로를 사용할 수 있다.

일부 입력 값에 대해서는 관심이 없는 경우가 많으며 표는 작게 유지하는 것이 좋으므로 🤷 DON'T Care가 존재한다. 이 진리표의 🤷 don't care항은 출력이 모든 입력 값에 의존하지는 않는 논리함수요소이다.

🎮 주제어 유닛의 설계 🎮

이제까지 기능 코드와 2비트 신호를 제어 입력으로 사용하는 ALU를 어떻게 설계하는가를 설명했다. 이제 나머지 제어 유닛을 살펴볼 것인데 다음과 같은 사안에 집중해보자.

✔️ OPCODE라고 불리는 OP필드는 항상 비트 31:26에 포함된다. 이 필드를 op(5:0)라고 부른다.
✔️ 읽을 레지스터 두 개는 항상 rs, rt 필드에 의해 지정된다. rs, rt 필드는 비트 25:21과 비트 20:16에 나타난다. 이것은 R형식 명령어, 같을 시 분기 및 저장 명령에 사용된다.
✔️ 적재 명령어와 저장 명령어를 위한 베이스 레지스터는 항상 비트 25: 21(rs)에 있다.
✔️ 같을 시 분기, 적재, 저장 명령어를 위한 16비트 변위는 항상 비트 15:0에 있다.
✔️ 목적지 레지스터는 두 곳 중 하나에 있다. 적재 명령어에서는 비트 20:16(rt)에 있고 R형식 명령어에서는 비트 15:11(rd)에 있다. 따라서 쓰기가 행해질 레지스터 번호로 명령어의 어느 필드를 사용하질지 선택하기 위해 멀티플렉서를 추가해야 한다.

위에서는 1비트 제어선 7개와 2비트 ALUOp제어 신호 하나가 있다. ALUOp제어 신호의 동작은 이미 정의, 명령어를 실행할 때 이 제어신호들 값을 어떻게 설정할지 결정하기 전에 이 제어신호들이 무슨 일을 하느지 정의하는 것이 좋다.

위에서 7개의 제어선 기능을 설명하고 있다. 제어선 각각의 기능에 대해서 살펴봤으니 이제 제어선 값을 어떻게 활용하는지 알아보자. 제어 유닛은 제어 신호 중 하나를 제외한 나머지 모두를 명령어의 opcode필드만 보고 결정할 수 있다. PCsrc제어선만은 예외다.

제어 유닛에 대한 수식이나 진리표를 작성하기 전에 제어 기능을 간략하게 정의하는 것이 유익하다. 제어 신호 값은 opcode에만 의존하기 때문에, 각각의 opcode값에 대하여 각 제어 신호가 0, 1, 🤷 don't care중 어느 값이 되어야 하는지를 정의한다. 아래 그림은 각각 opcode에 대해 어떤 값이 되어야 하는지를 나타낸다.


🔥 교재를 던지고 싶지만 그래도 이것이 가장 잘 설명된 자료다. 버티자 🔥

데이터 패스의 동작 🏇🏇🏇

앞선 정보를 바탕으로 제어 유닛의 논리회로를 설계할 수 있다. 그러나 설계에 들어가기 전에 각각의 명령어가 데이터 패스를 어덯게 사용하는 지를 살펴보자. 다음 몇 개의 그림에서 세 가지 명령어 종류들이 데이터 패스를 통과하는 흐름을 보인다. 각각의 그림에서 인가된 제어신호와 활성화된 데이터패스 구성요소는 진하게 표시하였다. 제어가 0인 멀티플렉서는 비록 제어선이 진하게 표시되지 않았더라도 분명하게 동작을 취한다는 점에 유의하자.


제어 유닛이 있는 간단한 데이터패스. 제어 유닛의 입력은 명령어의 6비트 opcode 필드이다. 제어 유닛의 출력은 멀티 플렉스를 제어하는데 쓰이는 세 개의 1비트 신호(RegDst, ALUSrc, MemtoReg), 레지스터 파일과 데이터 메모리에서 읽고 쓰는 것을 제어하기 위한 3개의 신호, 분기할지 말지를 판한다는 1비트 신호, ALU를 위한 2비트 제어신호이다.

위 그림은 ADD $t1, $t2, $t3와 같은 R형식 명령어의 데이터패스 동작을 보여주고 있다. 🔄 모든 일이 하나의 클럭사이클에 일어나지만, 명령어 실행을 네 단계로 생각할 수 있다. 이들 단계는 정보 흐름에 따라 순서가 결정된다.

  1. ➕ 명령어를 명령어 메모리에서 가져오고 PC값을 증가시킨다.
  2. 👁️‍🗨️ 두 레지스터 $t2, $t3를 레지스터 파일로부터 읽는다. 이 단계에서 주 제어 유닛이 제어선의 값들을 계산한다.
  3. 🧮 ALU는 레지스터 파일에서 읽어들인 값들에 대해 연산을 하는데 기능 코드(funct)를 사용해서 ALU 제어신호를 만든다.
  4. ✍🏽 ALU 결과 값이 레지스터 파일에 기록되는데, 목적지 레지스터($t1)는 명령어의 비트 15:11을 이용하여 선택한다.

적재 명령어

다음과 같은 워드 적재 명령어의 실행을 그림 4.19와 같은 방식으로 나타낼 수 있다.

lw $t1, offset($t2)

위의 적재 명령어를 위하여 활성화된 기능 유닛과 인가된 제어선들을 보여주고 있다. 적재 명령어는 다섯 단계로 동작하는 것으로 볼 수 있다. (R형식 명령어는 네 단계로 실행된다)

  1. ➕ 명령어를 명령어 메모리에서 가져오고 PC값을 증가시킨다.
  2. 👁️‍🗨️ 레지스터($t2) 값을 레지스터 파일로부터 읽는다.
  3. ➕ ALU는 레지스터 파일에서 읽어 들인 값과 명령어의 하위 16비트(OFFSET)를 부호확장한 값과의 합을 구한다.
  4. 🏘️ 이 합을 데이터 메모리 접근을 위한 주소로 사용한다.
  5. ✍ 메모리 유닛에서 가져온 데이터를 레지스터 파일에 기록한다. 목적지 레지스터($t1)는 명령어의 비트 20:16이 지정한다.

분기명령어 🚧

마지막으로 beq $t1, $t2, OFFSET와 같을 시 분기 명령어의 동작을 같은 방법으로 설명할 수 있다. 이 명령어는 R형식 명령어와 상당히 비슷하게 동작한다. 그러나 ALU 출력이 PC값이 PC+4로 바뀔 것인지 아니면 분기 목적지 주소로 바뀔 것인가 판단하기 위해 사용되는 것이 다르다. 그림은 실행의 네 단계를 보여주고 있다.

    1. ➕명령어를 명령어 메모리에서 가져오고 PC값을 증가시킨다.
    1. 👁️‍🗨️ 두 레지스터 $t1, $t2를 레지스터 파일로부터 읽는다.
    1. ➖ ALU는 레지스터 파일에서 읽어 들인 값들에 대해 뺄셈을 한다. 명령어의 하위 16비트를 부호 확장 후 2비트 왼쪽 자리이동한 값에다 PC+4 값을 더한다. 결과 값이 분기 목적지 주소이다.
    1. 어떤 덧셈기의 결과를 PC에 저장할지 ALU의 Zero 출력을 이용하여 판단한다.

제어 유닛의 완성


이제까지 명령어들이 단계별로 어떻게 동작하는지를 알아보았으니 이제는 제어 유닛의 구현에 대해 알아보자. 제어 기능은 줄 4개짜리 위 표를 보면 명확히 정의될 수 있다. 제어 유닛의 출력은 제어선들이며 입력은 6비트 opcode필드(Op[5:0])이다. 따라서 opcode의 이진수 인코딩을 이용하여 각 출력의 진리표를 만들 수 있다.

제어 유닛의 논리를 커다란 진리표 하나로 만든 것이 위의 그림이다. 이 표는 모든 출력을 망라하고 있으며 opcode비트들을 입력으로 사용하고 있다. 이것은 제어 기능을 완벽하게 명시하며 자동화된 방법을 이용하여 게이트로 곧바로 구현할 수 있다.

이제 MIPS핵심 명령어 집합에 대한 단일 사이클 구현(single-cycle implementation)을 완성하였으니, 명령어 집합의 다른 명령어를 처리하기 위해 어떻게 기본 데이터와 제어가 확장될 수 있는지를 보여주기 위해 점프 명령어를 추가하자.

단일 사이클 구현 단일 클럭 사이클 구현이라고도 한다. 명령어 하나를 한 클럭 사이클에 실행하는 구현. 이해가는 쉬우나 실제 사용하기에는 너무 느리다.

[점프 명령어 구현]

🦘 점프 명령어는 어떤 면에서는 분기 명령어와 비슷하지만 목적지 PC값 계산 방식이 다르고 또한 조건 분기가 아니라는 점이 다르다. 분기 명령어처럼 점프 명령어의 하위 2비트는 항상 00(two)이다. 32비트 주소 중 그 다음의 하위 26비트는 명령어의 26비트 수치 필드에서 나온다. 🏘️ 새 주소의 나머지 상위 4비트는 점프 명령어 주소에 4를 더한 값의 상위 4비트이다. 따라서 다음 세 개 값의 연접(concatenation)을 PC을 PC에 저장하면 점프 명령어를 구현할 수 있다.

  • 현재 PC+4의 상위 4비트(다음 명령어 주소의 비트 31:28)
  • 점프 명령어의 26비트 수치 필드
  • 비트 00(Two)

위의 그림은 점프 명령어를 위한 제어🎮가 추가된 것을 보여준다. 증가된PC값(PC+4), 분기 목적지 PC, 점프 목적지 PC 중에서 하나를 새로운 PC 값의 근원으로 선택하기 위해 멀티플렉서가 추가되었다. 이 추가된 멀티플렉서를 위해 제어 신호가 하나 추가로 필요하다. 이 제어신호(Jump라 불림)는 명령어가 점프, 즉 OPCODE가 2일 때만 인가된다.


단일사이클 구현은 오늘날 왜 사용되지 않는가?🙅‍♂️

⌛ 비록 단일 사이클 설계가 올바르게 작동한다고 하더라도 비효율성 때문에 현대적 설계에서는 쓰이지 않는다. 왜 그러한지는 너무 분명하다. 이 같은 단일 사이클 설계에서는 클럭 사이클이 모든 명령어에 대해 같은 길이를 가져야 하기 때문이다. 물론 클럭 사이클은 컴퓨터에서 가능한 경로 중 가장 긴 경로에 의해 결정된다.

이 최장 경로는 적재 명령어라는 것이 거의 확실하다. 적재 명령어는 명령어 메모리, 레지스터 파일, ALU, 데이터 메모리, 레지스터 파일의 다섯 개의 기능 유닛을 차례로 사용한다. CPI 값은 1이지만단일 사이클 구현은 클럭 사이클이 너무 길기 때문에 전체 성능은 좋지 않다. 😵‍💫

고정된 클럭 사이클을 갖는 단일 사이클 설계를 사용할 때 지불해야 될 대가는 엄청나지만 앞선 작은 명령어 집합에서는 받아들일 수 있을 만한 것으로 생각된다. 이같이 매우 간단한 명령어 집합을 가졌던 초창기 컴퓨터는 이러한 구현 방법을 사용하였다. 그러나 부동 소수점 유닛을 구현하려 하거나 좀 더 복잡한 명령어를 갖는 명령어 집합인 경우에는 단일 사이클 구현은 잘 작동하지 않을 것이다.

🚀 클럭 사이클은 모든 명령어에 대한 최악의 지연과 같다고 가정해야 하기 때문에, 흔한 경우의 지연은 줄여주지만 최악의 경우 사이클 시간은 개선하지 못하는 구현은 소용이 없다. 따라서 단일 사이클 구현은 자주 생기는 일을 빠르게라는 1장의 핵심 설계 원칙을 위반한다.

다음 절에는 파이프라이닝이라는 또 다른 구현 기술을 살펴볼 것이다. 단일 사이클 데이터패스와 매우 유사한 데이터패스를 사용하지만, 처리율이 훨씬 크기 때문에 매우 효율적이다. 파이프 라이닝은 여러 개의 명령어를 동시에 실행하여 효율을 높인다.

수정  
1013 
* 오타 수정 (한느=>하는)
* 이모지 추가 

0개의 댓글