앞의 글을 읽으시면 이해에 도움이 됩니다.
2022.09.23 - [Computer Science/컴퓨터 구조] - [컴퓨터 구조] Introduction to Computre Architecture (컴퓨터 구조의 소개)
1. Computer's Language
컴퓨터의 언어를 Instruction 이라고 합니다.
그것들의 단어장을 Instruction set이라고 합니다.
아무튼 이런 Instruction은 어셈블리어 혹은 기계어라고 불립니다.
기계어는 기계가 바로 이해할 수 있는 이진수로 이루어진 코드입니다.
이번 글에서는 어셈블리어가 무엇인지, 그리고 기계어와 왜 동일시되는지에 대해 적고, 명령어 집합에 대해 적겠습니다.
1.1 어셈블리어란?
어셈블리어는 기계어와 일대일 매칭이 되는 명령어입니다.
즉 어셈블리어 하나의 명령어가 기계에 직접적인 명령을 내린다고 볼 수 있습니다.
간혹 컴퓨터 공학과를 전공하거나 이래저래 찾아보면, 고급 언어 -> 어셈블리어 -> 기계어라고 설명하는 것 같습니다.
크게 보면 틀린 말은 아니지만, 정확히는 컴파일러마다 다릅니다.
"우리가 고급 언어로 프로그램을 만들면, 컴파일러가 이를 해석해서 어셈블리어로 만듭니다.
이 어셈블리어는 또 다시 어셈블러를 통해 기계어로 번역됩니다."
라고 보통 설명하지만, 대부분의 경우에는 고급 언어 -> 중간 언어 -> 어셈블리어 = 기계어라고 보면 될 것 같습니다.
그렇다면 왜 어셈블리어랑 기계어랑 따로 구분 지어 놓았을까요?
이유는 다음과 같습니다.
사실상 일대일 대응이라 둘을 구분할 필요는 없다.
다만 기계어를 보기 좋게 하기 위해 어셈블리어가 있는 거고,
만약 어셈블리어로 작성된 문서를 해석하려면 어셈블러를 통해야 한다
실제로 CPU가 잘못된 행동을 했을 때, 그것을 검사, 디버깅을 해야 합니다.
하지만 기계어를 일일이 해석할 수 없는 노릇이기에, 디버깅을 하기 위해 어셈블리어를 인위적으로 생성해서 검사합니다.
하지만 모든 컴파일러가 또 그런 것은 아니고,
어떤 컴파일러는 또 어셈블리어를 생성해서 그것을 어셈블리를 통해 기계어로 번역하는 컴파일러도 있습니다.
대표적인 예시로 C언어가 그렇습니다.
자세한 얘기는 뒤에서 하도록 하고, 아무튼 비로소 기계어를 통해 하드웨어가 명령을 수행합니다.
고급 언어는 컴파일을 하는 시간이 오래 걸린다는 단점이 있지만,
만약 어셈블리어로 이루어진 코드가 있다면, 어셈블리어는 기계어와 가장 가까운 언어기 때문에 컴파일한다 해도 굉장히 빠른 시간에 실행을 할 수 있습니다.
큰 진행 방향을 알기 위해 C언어에서의 컴파일 및 프로그램 실행에 대해 알아보겠습니다.
(아래는 어셈블리어의 필요성에 대한 글)
(어셈블리어는 사실 프로그램을 실행할 때 생성되지 않는다. 다만 개발자의 디버깅이나 검사를 위해 생성할 수는 있다.)
교수님께 어셈블리어의 필요성에 대해 질문드린 내용)
실제로 컴파일하는 과정에는 프론트 엔드, 백엔드가 있다.
프론트엔드는 보통 고급 언어를 중간 언어로 컴파일 하는 역할을 하고,
백엔드는 중간 언어를 기계어로 컴파일 하는 역할을 한다.
여기서 어셈블리어가 생길 수도 있고, 안 생길 수도 있다. 그건 컴파일러마다 다르다.
보통 프론트 엔드를 컴파일러가 담당하는데, 이때 컴파일러가 백엔드까지 다 해버리는 경우가 있다.
아무튼 여기에서 중요한 건 컴파일러마다 옵션이 있어서, 여기서 어셈블리어를 생성해도 되고, 안 해도 된다.
1.2 C언어에서의 컴파일 및 프로그램 실행
C 프로그램이 컴파일이 되어 어셈블리어 명령어가 된 모습을 볼 수 있습니다.
다만 이때 중요한 건 Linker라는 특이한 애가 존재하고, 얘가 다른 라이브러리와 내가 만든 어셈블리어를 연결시켜 준다는 점이 중요합니다.
위에서 설명했다시피, 고급언어 -> 기계어는 굉장히 시간이 오래 걸리기 때문에,
이미 어셈블리어나 기계어로 번역해놓은 라이브러리가 있다면 그것을 이용하는 것이 속도 면에서 매우 유리합니다.
그렇기 때문에 C를 변환한 어셈블리어는 어셈블러를 통하여 obj 파일이 되고,
이때 stdio.h 같은 라이브러리 파일은 이미 obj 파일로 존재하기 때문에, 이를 합쳐주는 것이 Linker의 역할입니다.
다만 이때 C 프로그램이 컴파일되어 어셈블리어가 된 것은 조금 더 특이한데, 여기에는 pseudoinstruction이 들어갑니다.
실제로 어셈블리어 명령어에 mv라는 명령어는 없지만, 간략화하기 위하여 mv라는 명령어를 사용하며,
이 명령어는 어셈블러가 해석해서 기계가 이해할 수 있는 언어로 바꿔줍니다.
(자세한 건 나중에 C에 대해 설명할 때 쓰겠습니다.)
2. Instruction
Instruction은 processor의 작동을 설명하는 가장 basic command입니다.
즉 instruction은 하드웨어와 소프트웨어의 인터페이스를 담당합니다.
이때 이 instruction은 Opcode, Operands로 이루어져 있습니다.
- Opcode : what the instruction does, 즉 하드웨어가 어떤 작업을 할지에 대한 명령어입니다.
- Operands : the object of an operation, 하드웨어가 어떤 대상에 대해 작업을 할지에 대한 명령어입니다.
예를 들어 add $2, $4, $2가 있을 때, add가 opcode가 되고, $2, $4, $2가 operands가 됩니다.
만약 add = 00000000001111111, $2, $4, $2 = 01010100100001010000 이라면
이진수 또한 마찬가지로 opcode와 operand로 구성됩니다.
어떤 방식으로 어셈블리어, 기계어는 하드웨어와 소통을 할 수 있을까요?
바로 ISA라는 Interface 덕분에 가능합니다.
ISA란 Instruction Set Architecture의 줄임말입니다.
CPU가 이해할 수 있는 instruction의 집합이라는 뜻입니다.
앞 글에서 ISA가 하드웨어와 소프트웨어의 인터페이스라고 간략하게 설명드렸습니다.
ISA는 CPU마다 모두 다르지만, 매우 비슷한데 이유는 다음과 같습니다.
- 비슷한 이론에 근본을 둔 비슷한 하드웨어 기술
- 몇몇 흔한 명령어와 기본적인 명령어(add ..)는 모든 컴퓨터가 제공해야 한다.
CPU 제조사마다 본인 회사가 만드는 CPU가 다르고, 같은 회사라도 CPU마다 다르기 때문에 ISA는 모두 다릅니다.
이때 동일한 프로그램이 다른 CPU에서 돌아가게 해주는 것이 바로 ISA입니다.
ISA는 매우 많은데, ARM 기반의 ARMv7, ARMv8 이 있고, 아무튼 다양합니다.
우리는 RISC-V에 대해 알아볼 겁니다.
3. Microarchitecture
Microarchitecture는 ISA의 구현이라고 보면 될 것 같습니다.
같은 걸 설계해도 미세하게 다른 것처럼, 같은 칩을 써도 Intel, AMD가 다르게 설계하는 것처럼
내부적으로 세세한 디테일이 다릅니다.
이런 것을 일일이 구현하는 것을 microarchitecture이라고 보면 됩니다.
실제로 같은 ISA를 사용하지만, microarchitecture은 전혀 다른 경우가 있습니다.
같은 ISA를 구현한다 해도 파이프라인의, 캐시 등등 다양한 요소에 차이을 두어서 다양한 프로세서를 만들 수 있습니다.
x86 ISA는 286, 386, ..., Pentium, Core i series 등등 수많은 구현 버전이 있습니다.
microarchitecture 안에서는 소프트웨어에게 보이지 않고, 안에서 모든 것을 처리할 수 있는 구조를 가지고 있습니다.
- PipeLining
- Speculative execution (추측 실행)
- Memory Access Scheduling
- Arithmetic units
등등..
아무튼 microarchitecture는 여기까지 하고, 대표적인 ISA 두 개를 비교하고, 글을 끝내겠습니다.
4. CISC vs RISC
CISC
- Complex Instruction Set Computer
- micro architecture에게 명령을 내리는데 필요한 모든 명령어 셋을 갖추고 있는 ISA이다. 따라서 복잡하고 기능이 많은 명령어로 구성되어있다.
- 과거에는 컴퓨터 메모리 용량이 크지 않아서 sw 프로그램의 용량을 줄이기 위해 하나의 명령어로 여러 작업을 수행하도록 했기 때문에 CISC를 많이 사용하였다.
- [장점] 복합적이고 기능이 많기 때문에 하위 호환성이 좋다. 즉 복잡한 명령어를 이미 하드웨어 수준에서 구현해 두었기 때문에, 어셈블리어 프로그래밍이 쉽다. 따라서 컴파일러가 단순하다.
- [장점] 또한 명령어가 비교적 간단하게 끝날 수 있으므로, instruction memory의 사용량이 감소한다.
- [단점] 하지만 각종 명령어를 하드웨어 수준에서 구현해야 하기 때문에 CPU design이 어렵다.
- [용도] 다양한 명령어들을 포함하고 있어 일반적으로 우리가 사용하는 범용 컴퓨터(general-purpose computer)의 CPU로 많이 사용된다.
RISC
- Reduced Instruction Set Computer
- CISC 내부에 갖추어진 모든 명령어들 중 불과 20%에 해당하는 명령어들만이 전체 80% 이상의 일을 처리한다. 따라서 CISC와 같이 필요한 모든 명령어 셋을 갖고 있는 것은 비효율적일 수 있다. 이를 극복하기 위해 등장한 것이 RISC이다
- [장점] RISC는 적은 수의 명령어들(사용 빈도가 높은 20%의 명령어들)로 구성된 processor이다. 따라서 CISC보다 더 빠른 속도로 동작할 수 있으며, 단순하고, 전력 소모가 적고, 가격도 저렴하다.
- [장점] CPU의 구현이 간단하다.
- [단점] 하지만 하드웨어가 간단한 대신 소프트웨어가 크고 복잡해졌으며, 하위 호환성이 부족하다는 단점이 있다. 즉 간단한 작업도 하드웨어는 단순한 명령만 처리하기 때문에, 소프트웨어가 이를 처리해야 한다.
- [단점] 어셈블리어 언어가 대체적으로 길다. 따라서 instruction이 많아지기 때문에 메모리 사용량이 증가할 수 있다.
- [용도] RISC 구조는 파이프라인 중첩이 가능해서 같은 수의 명령어에 대해 적은 clock으로 처리가 가능하며 발열과 전력 소모도 줄일 수 있다. 따라서 임베디드 프로세서에서는 RISC 구조를 많이 사용한다. (MIPS, ARM)
근데 RISC-V는 좋대요
아무튼 어셈블리어와 연관된 간단한 소개는 여기까지 하겠습니다.
다음 글에서는 명령어와 레지스터, 메모리의 관계에 대해 설명하겠습니다.
감사합니다.
지적 환영합니다.
'Computer Science > 컴퓨터 구조' 카테고리의 다른 글
[컴퓨터 구조] Procedure call, jal, jalr (프로시저 콜을 위한 명령어들) (2) | 2022.10.21 |
---|---|
[컴퓨터 구조] Decision Instruction (4) | 2022.10.21 |
[컴퓨터 구조] Type of Instruction (명령어의 타입) (2) | 2022.10.01 |
[컴퓨터 구조] RISC-V 명령어 작동 과정 (RISC-V Instruction Operation Process) (3) | 2022.10.01 |
[컴퓨터 구조] Introduction to Computer Architecture (컴퓨터 구조의 소개) (0) | 2022.09.23 |