티스토리 뷰

4. 프로세서 구조

이 장에서는 프로세서 하드웨어의 설계를 간단히 살펴본다. 하드웨어 시스템이 어떻게 특정 ISA의 인스트럭션들을 실행할 수 있는지를 학습한다. 이러한 관점은 어떻게 컴퓨터들이 동작하는지와 컴ㅍ터 제작자들이 직면하고 있는 기술적인 도전들을 더 잘 이해할 수 있게 해줄 것이다. 한 가지 중요한 개념은 최신 프로세서가 동작하는 실제적인 방법은 ISA에 의해 내포되는 계산모델과는 상당히 다를 수 있다는 것이다. 이 ISA 모델은 각 인스트럭션이 읽힌 후 다음 인스트럭션이 시작되기 전에 실행이 완료되는 순차적 인스트럭션 실행을 의미하는 것일 수 있다. 다수의 인스트럭션들의 서로 다른 부분을 동시에 실행함으로써 한 번에 한 개의 인스트럭션을 실행하는 것보다 높은 성능을 얻을 수 있다.
프로세서 설계는 왜 공부해야할까?

  • 지적으로 흥미롭고 중요하다. 어떤 일들이 어떻게 동작하는지 배우는 것 자체에 고유의 가치가 있다.
  • 프로세서의 동작방법을 이해하면 전체 컴퓨터 시스템의 동작 방법을 이해하는데 도움을 준다.
    이번 장에서는 예제로 사용할 간단한 인스트럭션 집합을 정의하는 것으로 시작한다. 이것을 Y86-64 인스트럭션 집합이라고 부른다. 이 집합은 x86-64에 비해 적은 자료형, 인스트럭션, 주소지정모드를 갖지만 정수형 데이터를 처리하는 간단한 프로그램을 작성할 수 있을 정도로 완전하다.
    순차 설계를 기초로 파이프라인형 프로세서를 만드는 일련의 변환을 적용한다. 각 인스트럭션의 실행단계를 5단계로 나누어서 각각 별도의 부분 또는 하드웽 단계에서 처리되도록 한다. 그 결과 프로세서는 동시에 최대 5개 인스트럭션까지 서로 다른 단계를 실행할 수 있다. 순차적 동작을 유지하도록 하기 위해서는 여러 가지 hazard 조건을 처리해야 한다. 이 조건들은 어떤 인스트럭션의 위치나 오퍼랜드들이 파이프라인 내에 남아 있는 다른 인스트럭션의 오퍼랜드에 의존하는 경우이다.

4-1. Y86-64 인스트럭션 집합

Y86-64와 같이 어떤 인스트럭션 집합을 설계하기 위해서는 여러 가지 상태요인들, 인스트럭션 집합과 이들의 인코딩, 프로그래밍 관습들, 예외적 사건들의 처리 등에 대한 정의를 해야한다.

4.1.1 프로그래머-가시성 상태 (Programmer-visible state)

Y-86-64의 각 인스트럭션은 프로세서 상태의 일부를 읽거나 변경할 수 있다. 이것을 프로그래머-가시성 상태(programmer-visible state)라고 한다. 이 경우 '프로그래머'는 프로그램을 어셈블리 코드로 작성하는 사람이거나 기계수준 코드를 생성하는 컴파일러이다.
Y86-64에는 15개의 프로그램 레지스터가 존재한다. 이 레지스터들은 각각 64비트 워드를 저장한다. 레지스터 %rsp는 push, pop, call, return 인스트럭션을 사용할 때 스택 포인터로 이용된다. 그 이외의 경우에 레지스터들은 정해진 의미나 값을 갖지 않는다. ZF, SF, OF로 이루어진 세 개의 조건 코드는 한 비트로 이루어져 있으며, 가장 최근에 수행한 산술 또는 논리연산의 결과에 관한 정보를 저장한다. PC는 현재 실행되고 있는 인스트럭션 주소를 보관하고 있다.
메모리는 개념적으로 커다란 바이트의 배열이며, 프로그램과 데이터 모두를 저장한다. Y86-64 프로그램들은 가상주소를 사용하여 메모리 위치를 참조한다. 운영체제와 하드웨어가 함께 이 가상주소를 실제 주소인 물리 주소로 번역한다.
마지막 부분은 상태코드 Stat이다. 이것은 정상 혹은 예외 상황이 발생했는지 등 프로그램 실행의 전체적인 상태를 나타낸다.

4.1.2 Y86-64 인스트럭션

  • movq 인스트럭션은 irmovq, rrmoveq, mrmoveq, rmmoveq의 네 개의 인스트럭션으로 나누어진다. 이들은 소스와 목적지를 명시적으로 나타낸다. 소스는 인스트럭션 이름의 첫 번째 문자로 나타내며 상수 immediate(i), register(r), memory(m) 중의 하나가 될 수 있다. 목적지는 인스트럭션 이름의 두 번째 문자로 나타내며 register(r)이나 memory(m)이 될 수 있다.
  • addq, subq, andq, xorq 의 네 개의 정수 연산이 있다. 이들은 오직 레지스터 데이터에만 연산을 할 수 있다. 이 인스트럭션 집합은 ZF, SF, OF 조건코드를 결정한다.
  • jmp, jle, jl, je, jne, jge, jg의 일곱 개의 jump 인스트럭션이 있다. 분기의 종류와 조건코드의 상태에 따라 분기가 이루어진다.
  • cmovle, cmovl, cmove, cmovne, cmovge, cmovg의 여섯 개의 move 인스트럭션이 있다. 이들은 레지스터-레지스터 move 인스트럭션 rrmovq 같은 형식을 같지만 목적지 레지스터는 조건코두가 요구된 조건을 만족할 때에만 갱신된다.
  • call인스트럭션은 리턴 주소를 스택에 넣고 목적지 주소로 이동한다. ret 인스트럭션은 call에서 리턴해준다.
  • pushqpopq는 동일하게 push와 pop을 구현한다.
  • halt인스트럭션은 인스트럭션의 실행을 정지시킨다.

4.1.3 인스트럭션 인코딩

그림 4.2 처럼 각 인스트럭션은 필요한 필드에 따라 1~10바이트까지 사용한다. 각 인스트럭션은 첫 번째 바이트를 사용하여 인스트럭션의 타입을 사용한다. 이 바이트는 상위의 _코드 부분_과 하위의 _기능 부분_의 두 개의 4비트 필드로 나뉜다. 기능 값은 인스트럭션 그룹이 공통된 코드를 공유하는 경우에 의미를 갖는다.

위의 그림에서 볼 수 있는 것처럼 15개의 프로그램 레지스터는 각각 0~0xE까지의 레지스터 식별자(ID)를 갖는다. 프로그램 레지스터들은 CPU 내의 레지스터 파일에 저장된다. 레지스터 파일은 레지스터 ID가 주소로 이용되는 작은 크기의 RAM이다. 0xF는 레지스터에 접근하지 말아야 한다는 것을 나타낼 필요가 있을 때 사용된다. 예를 들어 irmovq, pushq, pop 와 같이 한 개의 레지스터 오퍼랜드만을 필요로 하는 인스트럭션들은 다른 레지스터 식별자를 0xF로 설정한다.
예시로 이해해보자.
인스트럭션 rmmovq %rsp, 0x123456789abcd(%rdx)의 바이트 인코딩을 16진수로 만들어보자. 그림 4.2로부터 rmmovq는 첫번째 바이트로 40을 갖는다는 것과 소스 레지스터 %rsprA필드에, 베이스 레지스터 %rdxrB 필드에 인코딩되어야 한다는 것을 알 수 있다. 이를 그림 4.4의 레지스터 번호를 사용하여 레지스터 지정바이트 42를 얻는다. 마지막으로 0x123456789abcd를 8바이트로 만들기 위해 앞부분을 0으로 채우면 00 01 23 45 67 89 ab cd가 된다. 이것을 바이트-역순으로 cd ab 89 67 45 23 01 00으로 쓴다. 이들을 합치면 4042cdab896745230100을 얻는다.

4.1.4 Y86-64 예외상황

Y86-64에서는 Stat 상태코드를 사용하여 현재 실행하고 있는 프로그램의 전체적인 상태를 확인할 수 있다.

  • AOK: 정상적으로 실행되고 있음.
  • HLT: 프로세서가 halt 인스트럭션을 실행.
  • ADR: 잘못된 메모리 주소에서 읽어오거나 쓰려고 한 것.
  • INS: 잘못된 인스트럭션 코드를 만남.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함