이전 페이지에서 MIPS 명령어 일부를 지원하는 단순한 데이터 경로(Datapath)를 봤다면, 이번 페이지에서는 Datapath 위에 Control logic(제어 로직)을 추가하여 실제로 명령어를 실행할 수 있는 구조를 구현해본다.
MIPS의 ALU(Arithmetic Logic Unit)는 명령어 종류에 따라 다양한 연산을 수행해야 한다. 이를 위해 ALU에서는 4바트의 제어 신호가 입력되며, 이 신호 값에 따라 다음과 같은 연산 중 하나를 선택하여 수행한다.
| ALU Control (4비트) | 수행 연산 |
|---|---|
0000 | AND |
0001 | OR |
0010 | ADD |
0110 | SUBTRACT |
0111 | SET ON LESS THAN (SLT) |
1100 | NOR (확장용) |
각 명령어 클래스에 따라 ALU는 고정된 연산을 수행하거나, R-type 명령어의 funct 필드에 따라 동작이 달라진다.
예를 들어, R-type 명령어에서의 funct 필드가 100000 이면 add 연산이 필요하고, 100010이면 sub 연산이 필요하다. ALU는 이 funct 값을 기반으로 연산을 선택하며, 이를 위해 ALU Control 유닛은 다음 두 가지 입력을 기반으로 작동한다.
이 두 값을 이용해, 조합 논리 회로는 최종 4비트의 ALU Control 신호를 생성한다.
| 명령어 종류 | ALUOp | funct | ALU 연산 | ALU Control |
|---|---|---|---|---|
| lw/sw | 00 | X | add (주소 계산) | 0010 |
| beq | 01 | X | subtract (비교) | 0110 |
| R-type | 10 | 100000 | add | 0010 |
| R-type | 10 | 100010 | subtract | 0110 |
| R-type | 10 | 100100 | and | 0000 |
| R-type | 10 | 100101 | or | 0001 |
| R-type | 10 | 101010 | set on less than | 0111 |
ALU Control Unit이 ALUOp와 funct 필드를 사용하여 ALU 동작을 결정하고, 그 외 나머지 제어 신호를 생성하는 유닛이 Main Control Unit이다. 이 유닛은 명령어의 opcode 필드(31~26비트)를 기반으로, datapath의 구성 요소들을 제어하기 위한 여러 신호를 생성한다.

위 명령어 형식을 바탕으로, 제어 유닛은 아래의 사실들을 활용하여 설계된다.
따라서 목적지 레지스터를 선택하는 RegDst Mux와, ALU 입력을 정하는 ALUSrc MUX가 반드시 필요하다.
| 제어 신호 | 비트 수 | 설명 |
|---|---|---|
| RegDst | 1비트 | 목적지 레지스터 선택: rd(1) or rt(0) |
| ALUSrc | 1비트 | ALU의 두 번째 입력 선택: 레지스터 rt(0) or 즉시값(1) |
| MemtoReg | 1비트 | 메모리 값 or ALU 결과를 레지스터에 저장 |
| RegWrite | 1비트 | 레지스터 파일 쓰기 여부 |
| MemRead | 1비트 | 메모리 읽기 수행 여부 |
| MemWrite | 1비트 | 메모리 쓰기 수행 여부 |
| Branch | 1비트 | 분기 수행 여부 |
| ALUOp | 2비트 | ALU 제어 동작 지정용 (ALU Control 유닛으로 전달됨) |
Control Unit은 명령어의 opcode 필드(31:26, 6비트)를 유일한 입력값으로 받는다. 이 단 하나의 입력만으로도 위와 같은 제어 신호들을 만들어낸다.
ALUOp는 ALU Control 유닛에 입력되어 최종 ALU 연산 제어 신호(4비트)를 만든다.
분기 명령어(beq)의 경우 다음 명령어의 주소 선택은 아래 조건에 따라 달라진다.
이 두 신호는 AND 게이트를 통해 결합되고, 그 결과가 PCSrc 신호를 만들어낸다. 따라서 PCSrc는 Control Unit의 직접 출력이 아니며, 하드웨어 내에서 유도되는(derived) 신호이다. 아래 회로도에서 PCSrc는 생략되며, 대신 Zero And Branch의 결과가 MUX에 연결되어 PC를 갱신할지 결정하게 된다.

Control Unit의 역할 요약
1. 명령어 fetch 후, Control Unit은 opcode를 입력받는다.
2. 각 제어 신호를 설정하여, MUX, ALU, 레지스터 파일, 메모리 등을 동작시킨다.
3. ALU 연산 제어는 ALUOp를 통해 ALU Control이 결정한다.
4. 분기인 경우, ALU Zero 출력과 Branch 신호가 결합되어 다음 PC 주소를 결정한다.

//Example
add $t1, $t2, $t3
Step 1: 명령어 가져오기(Instruction Fetch) : Program Counter(PC)의 값이 명령어 메모리에 주소로 전달되어 명령어가 읽혀진다. 동시에 PC + 4가 계산되어 다음 명령어의 주소를 준비한다.
Step 2: 레지스터 읽기 및 제어 신호 생성 : 명령어에서 rs, rt 필드를 해석하여 해당 레지스터($t2, $t3)를 레지스터 파일(Register File)에서 읽어온다. 동시에 Control Unit이 명령어의 opcode를 해석하여 다음 제어 신호들을 설정한다.
Step 3: ALU 연산 수행 : 레지스터에서 읽은 값 두 개($t2, $t3)를 ALU로 전달한다. ALU는 명령어의 funct 필드를 기반으로, 정확한 연산(add)를 수행한다. 이때 ALU Control Unit이 ALUOp=10과 funct를 조합해 ALU 제어 신호(0010 for add)를 생성한다.
Step 4: 결과 레지스터에 저장 : ALU 연산 결과가 레지스터 파일의 목적지 레지스터(rd=$t1)에 기록된다. 목적지 선택은 RegDst = 1로 인해 rd 필드(15:11)가 선택된다.
| 단계 | 주요 동작 | 제어 신호 | 주요 하드웨어 |
|---|---|---|---|
| 1 | 명령어 fetch 및 PC 증가 | - | PC, Instr Mem, Adder |
| 2 | 레지스터 읽기 및 제어 신호 설정 | RegDst, ALUSrc, ALUOp, RegWrite | Control Unit, RegFile |
| 3 | ALU 연산 (funct 기반) | ALU Control | ALU, ALU Control |
| 4 | 결과 저장 (rd) | RegWrite, RegDst | RegFile, MUX |

//Example
lw $t1, 8($t2)
| 단계 | 주요 동작 | 제어 신호 | 주요 하드웨어 |
|---|---|---|---|
| 1 | 명령어 fetch 및 PC + 4 | - | PC, Instr Mem, Adder |
| 2 | $t2 읽기 및 제어 신호 설정 | ALUSrc = 1, ALUOp = 00, RegWrite = 1 | RegFile, Control Unit |
| 3 | 주소 계산: $t2 + offset | ALUSrc, ALUOp | ALU, Sign Extend, MUX |
| 4 | 메모리 읽기 | MemRead = 1 | Data Memory |
| 5 | 메모리 값 → $t1에 저장 | RegWrite = 1, MemtoReg = 1 | RegFile, MUX |

#Example
beq $t1, $t2, offset
# $t1==$t2이면, PC <- PC + 4 + (offset x 4)
Step 1: 명령어 가져오기(Instruction Fetch) : 현재 PC를 이용해 명령어 메모리에서 beq 명령어를 가져온다. 동시에 PC + 4를 계산하여 기본적으로 다음 명령어 주소를 준비한다.
Step 2: 레지스터 읽기 : 명령어의 rs와 rt 필드(25:21, 20:16)를 이용해 $t1, $t2 값을 레지스터 파일에서 읽어온다. 동시에 Control Unit이 opcode = 000100(beq)을 해석하여 제어 신호를 설정한다.
Step 3: 비교 및 분기 주소 계산 : ALU는 $t1 - $t2 연산을 수행하여 Zero 출력을 생성한다. 동시에, 명령어의 하위 16비트(offset)를 sign-extend -> shift-left-2하여 branch target offset을 생성한다. 이 offset을 PC + 4에 더하여 분기 대상 주소를 계산한다.
Step 4: 다음 명령어 주소 설정 : ALU에서 Zero 출력이 1이면(t2), Control Unit의 Branch 신호도 1이므로 AND 게이트 출력이 1, PC는 branch target으로 설정된다. 조건이 거짓이면 AND 게이트 출력이 0이므로 PC는 그냥 PC + 4가 된다.
| 단계 | 주요 동작 | 제어 신호 | 주요 하드웨어 |
|---|---|---|---|
| 1 | 명령어 fetch 및 PC + 4 | - | PC, Instr Mem, Adder |
| 2 | $t1, $t2 읽기 및 제어 신호 설정 | Branch = 1, ALUOp = 01 | RegFile, Control Unit |
| 3 | 비교 수행 및 분기 주소 계산 | ALUSrc = 0 | ALU, Sign Extend, Shift-left-2, Adder |
| 4 | 분기 조건 판단 → 다음 PC 결정 | Zero + Branch | AND, MUX for PCSrc |

PC ← { PC+4[31:28], target[25:0], 00 } - 상위 4비트 : PC + 4의 31:28 비트중간 26비트 : 명령어의 target 필드
하위 2비트 : 항상 00(워드 정렬 주소)
분기(branch) 명령어는 offset을 더하는 방식이었지만, jump는 아예 새로운 주소로 PC를 대체하는 구조이다.

| 항목 | 설명 |
|---|---|
| 명령어 형식 | opcode(6) + target(26) |
| 주소 계산 | {PC+4[31:28], target, 00} |
| 데이터 경로 확장 | shift-left-2, PC 상위 비트 병합, 추가 MUX |
| 제어 신호 | Jump (1비트) 신호 추가 |
| 차이점 | 조건 분기 아님 (ALU 사용 X, Zero 확인 X) |
| 명령어 | RegDst | ALUSrc | MemtoReg | RegWrite | MemRead | MemWrite | Branch | Jump | ALUOp |
|---|---|---|---|---|---|---|---|---|---|
| R-type | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 10 |
| lw | 0 | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 00 |
| sw | X | 1 | X | 0 | 0 | 1 | 0 | 0 | 00 |
| beq | X | 0 | X | 0 | 0 | 0 | 1 | 0 | 01 |
| j | X | X | X | 0 | 0 | 0 | 0 | 1 | XX |