ALU 제어신호에서 첫 번째 비트는 Ainvert, 두 번째는 Binvert, 뒤의 두 비트는 operation 종류를 명시하는 신호였다.
| control lines | function |
|---|---|
| 0000 | and |
| 0001 | or |
| 0010 | add |
| 0110 | subtract |
| ... | ... |
(전부 외우기보다는 그때그때 조건을 보면서 찾아내는 것이 좋다.)
명령어 타입에 따라 사용하는 ALU 연산이 다르다. 크게 세 그룹으로 나눌 수 있다.
Load/Store의 경우 메모리 주소를 찾고 값을 더하는 과정에서 add 연산을 활용한다.
Branch계통 명령어는 두 값의 크기를 비교해야 하므로 subtract 연산을 쓴다.
R-type은 func3과 func7에 따라 다양한 연산을 사용할 수 있다.
ALUOp 은 opcode에 따라 할당되는 ALU 제어 신호이다. R-type이 아닌 명령어는 ALUOp만 보고도 제어 신호를 생성할 수 있다.
ALUOp은 Control 이라는 컴포넌트에서 두 비트로 생성된다. 이후 나올 ALU control과는 다른 장치이다.
위에서 만든 그룹대로 명령어를 나눠보면 다음과 같다.
| l/s | branch | R-type |
|---|---|---|
| 00 | 01 | 10 |
| add | subtract | depends on func3/7 |
ALUOp을 사용하면, 컨트롤 패널이 func3/7을 입력받지 않고도 명령어의 종류를 구별할 수 있어 훨씬 간단하게 구현된다.
이처럼 기존의 컨트롤 모듈을 Control/ALU Control로 나눠서 메인 컨트롤 유닛의 사이즈를 줄이는 방법을 Multilevel decoding 이라고 한다.
예를 들어 load와 store는 동일한 opcode를 가지고 있다.
서로 다른 명령어지만 비슷한 체계로 움직이기 때문에 control에서 두 명령어를 같은 그룹으로 처리해도 괜찮다. 자세한 명령어는 ALU Control에서 만들어주기 때문이다.
addi
branch:0, MemRead:0, MemtoReg=0, ALUOp:00(이유:immed가 있어서)
memwrite:0, ALUSrc:1(0이면 r2에서 받아오고 1이면 ImmGen에서 받아오니까), RegWrite:1
-> 00000011
addi의 ALUOp
load/store 타입 인 00으로 매핑할 시 or, and와 묶일 수 있는데, addi는 funct3/7까지 봐야 하기 때문에 10 또는 11로 매핑하는 것이 적절하다.
명령어 중 가장 많은 느린 것은 load 이다.
그래서 clock period를 측정할 때는 load를 기준으로 삼는데, 그렇게 자주 쓰이는 명령어가 아닌데도 성능에 큰 영향을 끼치기 때문에 개선할 필요가 있다.
이 때 pipelining 이라는 기법을 활용한다.