[無에서 시작하는 컴퓨터&과학]

[컴퓨터][24] 제어장치 - 3 (스테퍼와 명령어, Stepper and Instruction )

core-basic 2024. 9. 30. 21:56
728x90

※ 해당 게시글은 주제를 탐구하면서 주관적인 생각을 정리 한 글입니다.
※ 해당 게시글은 J.클라크 스코트, 『그래서 컴퓨터는 어떻게 동작하나요?』, 지유록, 인사이트(2019) 책을 참고하였습니다. 


이전 글들을 통해서 

산술 논리 장치(ALU)와 클럭을 구현해 보았다.

그러면서 제어장치에 대해 좀 더 자세히 알게 되었다.

 

제어장치란 클럭 신호에 맞추어

각 장치의 입출력 제어기를 활성화하거나, 비활성화할 수 있도록 해주어,

외부 버스(Bus)로 데이터를 전송하거나, 버스(Bus)에 있는 데이터를 받을 수 있도록

조율해 주는 장치임을 알 수 있었다.

 

그리고 제어장치는 명령어를 해석하는 역할도 하는데,

"명령어를 해석한다"는 문장의 좀 더 직관적인 의미는

설계 목적에 따라

디코더를 입출력 제어기에 추가로 연결하여

클럭뿐만 아니라 특정 신호도 활성화 되어야 회로가 동작하도록 하여

회로에 대응되는 특정 신호를 사용자가 입력하면 

해당 신호에 대응되는 회로가 동작하는 것을 의미했다.

이때 ALU에서 각 연산 회로에 대응되는 특정 신호를 OPcode라 부른다.

 

[컴퓨터][22] 제어장치 - 1 (디코더 그리고 산술/논리 장치(ALU : Arithmetic and Logical Unit ))

※ 해당 게시글은 주제를 탐구하면서 주관적인 생각을 정리 한 글입니다.컴퓨터는 처음에 계산을 자동화하기 위해 산술/논리 연산 회로로 설계되었지만나눗셈 연산과 같이 중간 결괏값

core-basic.tistory.com

 

[컴퓨터][23] 제어장치 - 2 ( JK플립플롭과 클럭)

※ 해당 게시글은 주제를 탐구하면서 주관적인 생각을 정리 한 글입니다.이전 글을 통해서제어장치란 적절한 시점에 각 장치의 입출력제어기를 활성화하거나,비활성화할 수 있도록 해줌

core-basic.tistory.com

그러면 이어서 OPcode로 산술 논리 장치에서

어떤 연산자를 이용할지 선택할 수 있지만

자동 연산은 이루어지지 않았다.

그리고

복잡한 연산을 사용할 경우 ALU 연산 장치뿐만 아니라,

레지스터와 같은 메모리 장치도 사용된다.

이에 따라서 ALU 장치, 레지스터와 같은 메모리 장치 등 

각 장치를 선택하고 어떤 장치의 입출력제어기를 먼저 활성화할지

클럭에 맞추어 장치를 선택하고, 순서를 정해주어야 한다.

그리고

사용자가 장치를 선택할 수 있도록 대응되는

특정 이진수 신호를 제공해주어야 하는데

이것들을 어떻게 구현할 수 있는지 탐구해 보겠다.

< 제어장치 >
( 스테퍼와 명령어 )


< 제어장치 : ALU 연산 자동화 >

우선 제어장치를 통해

클럭 신호에 맞추어 ALU 연산 회로를 선택하고 연산하는 과정을

자동화하기 위해서는 다음과 같은 준비물이 필요하다.

1. 각 연산 회로에 대응되는 특정한 이진수 (OPcode)

2. 입력/출력 제어 클럭 신호 (clk_s, clk_e) 

해당 준비물들은 이전 글들을 통해 모두 구현할 수 있었다.

이에 따라

산술 논리 장치(ALU)에서 각 연산 회로의 입력 제어기는

입력 제어 클럭(clk_s)과 연결한다.

산술 논리 장치(ALU)에서  각 연산 회로의 출력 제어기는

출력 제어 클럭(clk_e) 연결한다.

그리고 OPcode와 AND 연산자로 연결하여,

OPcode에 대응되는 연산 회로만 연산 결과가 외부로 출력될 수 있도록 한다.

이를 회로로 보면 다음과 같다.

 

< A :1 , B : 1, OPcode : 101 (ADD) >

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

< 종합 클럭(clk_d, clk_e, clk_s)  기호화 >

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

이처럼 하나의 출력제어기를 활성화하고 비활성화하는 사이에,

하나의 입력제어기를 안전하게 활성화하고 비활성화할 수 있는데

해당 순서를 기본 클럭 단위(ex, 2Hz)로 설정하여

좀 더 자세히 살펴보면 다음과 같다.

 

[0초] clk_e = 0, clk_s = 0, OPcdoe = 101 (ADD)

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.


[1초] clk_e = 0 → 1, clk_s = 0, OPcdoe = 101 (ADD)

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.


[2초] clk_e = 1, clk_s = 0 → 1, OPcdoe = 101 (ADD)

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.


[3초] clk_e = 1, clk_s = 1 → 0, OPcdoe = 101 (ADD)

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.


[4초] clk_e = 1 → 0, clk_s = 0, OPcdoe = 101 (ADD)

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.


 [ 0초~4초 ]

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

이처럼 기본 클럭(clk) 신호에 맞춰 각 단계에서

하나의 출력제어기와 하나의 입력제어기를 조정하여

자동으로 연산 회로를 선택하고, 해당 장치의 입력과 출력을 조작할 수 있다.


< 제어장치 : 실질적인 ALU 연산 과정(누산기 : ACC) >

하지만 실질적으로 ALU 연산을 진행하기 위해서는

데이터를 저장하는 레지스터로부터 데이터(/값/피연산자)를 ALU로 전송하고,

ALU에서 연산을 진행한 후 연산 결과를 저장할 레지스터도 필요하다.

 

즉, 클럭 신호를 통해 적절한 타이밍에 맞추어 

특정 연산 회로의 출력제어기와 입력제어기를 

안정적으로 조작할 수 있게 되었지만,

실질적인 연산 과정에서는 ALU뿐만 아니라, 레지스터와 같은 메모리회로 등

다양한 장치가 연산에 사용되므로, 어떤 장치를 먼저 사용할 것인지 순서를 정해야 한다.

 

따라서 우선 ALU 연산 결과를 저장하는 레지스터(누산기, ACC :accumulator )

추가하면 다음과 같으며, 레지스터도 ALU와 똑같이

입력(Set) 부분은 입력 제어 클럭을 연결하고,

출력(Enable) 부분은 출력 제어 클럭을 연결하면 된다.

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

ALU 연산 결과를 저장하는 레지스터 : 누산기(ACC)는

연산의 중간 결괏값을 저장하고
이를 다음 연산에 빠르게 활용할 수 있다는 장점도 있다.

 

그리고 실질적인 제어장치 동작 과정을

출력 제어기가 활성화되고 비활성화되는 간격을 하나의 단계로

보았을 때 순서대로 살펴보면 다음과 같다.

ex)
A 레지스터의 값을 B레지스터의 값을 덧셈(ADD) 연산을 한 후
그 결과를 A 레지스터에 저장하기.
( [reg A] = [reg A] + [reg B] )

 

[1 단계]
A 레지스터 출력 제어기 활성화
→ ALU 입력제어기 활성화 

→ ALU 입력제어기 비활성화 →
A 레지스터 출력 제어기 비활성화

[2 단계]
B 레지스터 출력 제어기 활성화
→ [연산 바로 진행]
→ 연산 결과 저장 레지스터(누산기 : ACC) 입력 제어기 활성화
→ 연산 결과 저장 레지스터(누산기 : ACC) 입력 제어기 비활성화 →
B 레지스터 출력 제어기 비활성화 

 

[3 단계]
연산 결과 저장 레지스터 (누산기 : ACC)  출력 제어기 활성화
→ A 레지스터 입력제어기 활성화
→ A 레지스터 입력제어기 비활성화
연산 결과 저장 레지스터 (누산기 : ACC) 출력 제어기 비활성화

이와 같이 3단계를 통해 ALU연산이 이루어진다.

 

이때 중요한 점은

각 단계가 시작하고 끝나기까지의 시간 사이에,

출력 제어 클럭(clk_e)이 활성화되었다가 비활성화되고,

출력 제어 클럭(clk_e)이 활성화되었다가 비활성화되는 시간 사이에,

입력 제어 클럭이 활성화되었다가 비활성화된다.

이를 통해, 서로 다른 장치로부터 동시에 출력이 나오는 것을 방지하고,

출력과 입력이 충돌하는 것을 방지한다.

 

그리고 각 단계에서 입력 제어기가 활성화된 장치와

출력 제어기가 활성화된 장치는 다른 장치는 서로 다를 수 있다는 것이다.

이는 필요한 데이터가 다른 장치에서 입력되고,

연산 결과가 다른 장치로 출력되는 구조를 가능하게 한다.

 

이처럼 제어 신호들을 정밀하게 조율하기 위해서, ‘단계(Step)’가 필요하다.

이에 따라 "단계(Step)"을 정의해 주는 장치를 스테퍼(Stepper)라고 한다.


< 제어장치 : 스테퍼 >

다시 말해, 각 장치에 “단계(Step)” 이란 각 작업의 순서와 타이밍을 부여하여,

여러 장치가 동시에 충돌하지 않고 안정적으로 동작할 수 있도록 해준다.

그래서 실질적으로 스테퍼가 장치를 선택한다는 표현보다는,

선택된 장치들이 충돌 없이 연산을 진행되도록 제어 신호의 순서를 조율하는 것이다.

이때 장치를 선택하는 것은 OPcode(연산 명령 코드)와 같이
디코더를 통해 특정한 이진수 신호를 추가하여
스테퍼의 타이밍 신호와 AND연산을 함으로써 장치가 선택된다. 

이를 통해 복잡한 연산 과정에서도 정확한 장치 제어가 가능하다.

 

스테퍼를 구현하기 위해서 먼저

스테퍼의 신호를 클럭(clk, clk_s, clk_d)과 비교하여 살펴보면 다음과 같다.

단위 : 2Hz [0초] [1초] [2초] [3초] [4초] [5초] [6초] [7초]
clk 0 1 0 1 0 1 0 1
clk_d 1 1 0 0 1 1 0 0
clk_e 1 1 1 0 1 1 1 0
clk_s 0 1 0 0 0 1 0 0
스테퍼
[STEP 1]
1 1 1 1 0 0 0 0
스테퍼
[STEP 2]
0 0 0 0 1 1 1 1
스테퍼
[STEP 3]
0 0 0 0 0 0 0 0

※ 해당 이미지는 Paul falstad 사이트를 통해 제작하였습니다.

이처럼 스테퍼의 신호는 각 단계가 시작하고 끝나기까지 계속 활성화하여

그 활성화 시간 사이동안

출력 제어 클럭(clk_e)이 활성화되었다가 비활성화되고,

또, 출력 제어 클럭(clk_e)이 활성화되었다가 비활성화되는 시간 사이에,

입력 제어 클럭이 활성화되었다가 비활성화된다.

 

위와 같은 신호를 만들기 위해 과학자들은 다음과 같은 Stepper 회로를 발명하였다.

※ 해당 이미지는 Paul falstad 사이트를 통해 제작하였습니다.

해당 회로를 분석해 보면 다음과 같다. 이때 M = 메모리 회로(D플립플롭)이다.

단위 : 2Hz 0 → 1 1 → 2 2 → 3 3 → 4 4 → 5 5 → 6
clk 0 1 0 1 0 1
M1
[Set(clk)/Data/Q] 
[0/1/0] [1/1/0] [0/1/1] [1/1/1] [0/1/1] [1/1/1]
M2
[Set(clk)/Data/Q] 
[1/0/0] [0/1/0] [1/1/1] [0/1/1] [1/1/1] [0/1/1]
[STEP 1] 1 1 0 0 0 0
M3
[Set(clk)/Data/Q]  
[0/0/0] [1/0/0] [0/1/0] [0/1/1] [1/1/1] [0/1/1]
M4
[Set(clk)/Data/Q] 
[1/0/0] [0/0/0] [1/0/0] [0/0/0] [1/1/0] [1/1/1]
[STEP 2] 0 0 1 1 0 0
M5
[Set(clk)/Data/Q] 
[0/0/0] [1/0/0] [0/0/0] [1/0/0] [0/1/0] [1/1/0]
M6
[Set(clk)/Data/Q] 
[1/0/0] [0/0/0] [1/0/0] [0/0/0] [1/0/0] [0/1/0]
[STEP 3] 0 0 0 0 1 1

1초 후 M1(D 플립플롭)이 출력되면서, M2의 입력으로,

1초 후 M2가 출력되면서, M3의 입력으로,


이처럼, M1에 저장된 1 값이 1초 간격으로

다음 메모리에 전달되고, 또 이어서 그다음 메모리로 전달된다.

그리고,

[STEP 1]는 계속 활성화되었다가 M2_Q = 1일 때 STEP1 비활성화되고,

[STEP 2]는 M2_Q = 1 일 때 활성화 되고, M4_Q = 1이 되면 비활성화된다.

[STEP 3]도 M4_Q = 1 일 때 활성화 되고, M6_Q = 1이 되면 비활성화된다.

따라서 중간에 M3, M5는 의도적인 타이밍 신호를 구현하기 위해

STEP 활성화 신호를 좀 더 오래 유지하는 역할을 한다고 볼 수 있다.

 

그리고 마지막 스텝(STEP 4)의 활성화 신호를 활용하여

모든 D플립플롭(메모리 회로)에 S = 1, D = 0을 입력하여 초기화한다.

이는 스테퍼가 반복적으로 동작할 수 있도록 해준다.

하지만

입출력제어 제어 클럭이 활성화되는 시간과 타이밍을 맞추기 위해서는

사용되는 클럭이 기본클럭이 아닌, 지연 클럭(clk_d)을 사용되어야 한다.

이에 따라 JK플립플롭으로 구현한 clk_d, clk_e, clK_s

종합 클럭에서 clk_d를 앞서 구현한 스테퍼와 연결한다.

 

< JK플립플롭으로 구현한 종합 클럭 >

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

하지만 실질적으로는 마지막 스텝 이후 다시 처음으로 돌아오는 과정에 대해서

다음 그림과 같이, D플립플롭에 리셋 기능이 필요하다.

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

 리셋 기능이 추가된 D플립플롭은 다음과 같다.

※ 해당 이미지는 Paul falstad 사이트를 통해 제작하였습니다.

이처럼 스테퍼를 통해서 각 장치에

“단계(Step) : 각 작업의 순서와 타이밍"을 부여하여,

여러 장치가 동시에 충돌하지 않고 안정적으로 동작할 수 있도록 해준다.

이에 따라 다시 앞서 주어진 예시를

ALU회로 + 입출력 제어 클럭에 스테퍼까지 추가하면

다음과 같은 동작과정을 확인할 수 있다.

ex)

A 레지스터의 값을 B레지스터의 값을 덧셈(ADD) 연산을 한 후
그 결과를 A 레지스터에 저장하기
( [reg A] = [reg A] + [reg B] )

[1 단계]
A 레지스터 출력 제어기 활성화
→ ALU 입력제어기 활성화 

→ ALU 입력제어기 비활성화 →
A 레지스터 출력 제어기 비활성화

[2 단계]
B 레지스터 출력 제어기 활성화
→ [연산 바로 진행]
→ 연산 결과 저장 레지스터(누산기 : ACC) 입력 제어기 활성화
→ 연산 결과 저장 레지스터(누산기 : ACC) 입력 제어기 비활성화 →
B 레지스터 출력 제어기 비활성화 

 

[3 단계]
연산 결과 저장 레지스터 (누산기 : ACC)  출력 제어기 활성화
→ A 레지스터 입력제어기 활성화
→ A 레지스터 입력제어기 비활성화
연산 결과 저장 레지스터 (누산기 : ACC) 출력 제어기 비활성화

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

이처럼 ADD 연산뿐만 아니라,

모든 다른 연산도 같은 방법으로 연결하여 연산을 진행할 수 있다.

하지만 스테퍼는 선택된 장치들이 충돌 없이 연산을 진행되도록

제어 신호의 순서를 조율하는 것일 뿐

직접 장치를 선택하지 못한다.

위의 그림 역시, 사용할 장치들을 직접 스테퍼와 연결해 주었을 뿐이다.

 

그렇다면 연산에 사용할 장치들을 어떻게 선택할까?

장치를 선택한다는 것의 진정한 의미는 무엇인가?


< 제어장치 : 명령어 (명령어 해석 및 장치 선택) >

ALU에서는 특정 연산 회로를 디코더와 결합하여

특정한 이진수(OPcode)에 대응시킴으로써

사용자가 특정한 이진수(OPcode)를 입력하면 이에 대응되는

연산 회로의 출력 클럭 신호와 AND연산되어 출력이 활성화된다.

 

제어장치도 ALU와 레지스터 등 각 장치의 입출력제어기와 스테퍼를

디코더와 결합시키면

기존 ALU에만 국한되어 있던 OPcode를 확장시켜,

사용자가 특정한 이진수(명령어)를 입력하면

ALU와 메모리 회로(레지스터 등)와 데이터를 자동으로

주고받을 수 있도록 할 수 있다.

 

그리고 이때의 특정한 이진수를 “명령어”라고 부른다.

이에 따라 다시 OPcode를 살펴보면 다음과 같다.

입력(OPcode) 출력
CMP = 000 1000 0000
XOR = 001 0100 0000
NOT = 010 0010 0000
OR = 011 0001 0000
AND = 100 0000 1000
ADD = 101 0000 0100
SHL = 110 0000 0010
SHR = 111 0000 0001

그리고 이를 단순 연산자뿐만 아닌, 피연산자(레지스터 등)까지 포함하여,

초기 컴퓨터의 기본단위인 8bit로 명령어로 확장시키면

다음과 같이 구성될 수 있다.

[1] [000] [00] [00]

[명령어 종류]
1bit : [0] ~ [1]
[연산자:OPcode]
3bit : [000] ~ [111]
[RA : A레지스터]
2bit : [00] ~ [11] 
[RB : B레지스터]
2bit : [00] ~ [11] 
0 : ALU 이외의 명령어 CMP = 000 R0 = 00 R0 = 00
1 : ALU 명령어 XOR = 001 R1 = 01 R1 = 01
  NOT = 010 R2 = 10 R2 = 10
  OR = 011 R3 = 11 R3 = 11
  AND = 100    
  ADD = 101    
  SHL = 110    
  SHR = 111    
명령어 해석
1 000 [RA] [RB] CMP RA, RB RA와 RB를 비교연산 후 RA에 저장
1 001 [RA] [RB] XOR RA, RB RA와 RB를 XOR연산 후 RA에 저장
1 010 [RA] [RB] NOT RA, RA를 NOT 연산 후 RA에 저장
1 011 [RA] [RB] OR RA, RB RA와 RB를 OR연산 후 RA에 저장
1 100 [RA] [RB] AND RA, RB RA와 RB를 AND연산 후 RA에 저장
1 101 [RA] [RB] ADD RA, RB RA와 RB를 ADD연산 후 RA에 저장
1 110 [RA] [RB] SHL RA, RA를 SHL연산 후 RA에 저장
1 111 [RA] [RB] SHR RA, RA를 SHR연산 후 RA에 저장

이때 ALU 모든 연산은 위에서

예시로 언급하였듯이 다음 단계를 따른다.

[1 단계]
A 레지스터 출력 제어기 활성화
→ ALU 입력제어기 활성화 

→ ALU 입력제어기 비활성화 →
A 레지스터 출력 제어기 비활성화

[2 단계]
B 레지스터 출력 제어기 활성화
→ [연산 바로 진행]
→ 연산 결과 저장 레지스터(누산기 : ACC) 입력 제어기 활성화
→ 연산 결과 저장 레지스터(누산기 : ACC) 입력 제어기 비활성화 →
B 레지스터 출력 제어기 비활성화 

 

[3 단계]
연산 결과 저장 레지스터 (누산기 : ACC)  출력 제어기 활성화
→ A 레지스터 입력제어기 활성화
→ A 레지스터 입력제어기 비활성화
연산 결과 저장 레지스터 (누산기 : ACC) 출력 제어기 비활성화

따라서, 만약 디코더를 이용해 각 장치와 연결된

특정 이진수 신호와 OPcode, 그리고 입출력 제어 신호 클럭,

추가로 스테퍼에서
임의의 RA:A레지스터 신호,
임의의 RB:B레지스터 신호,
임의의 ALU 연산 신호,
를 각 단계에 맞게 연결하면

사용자가 입력한 명령어에 따라 대응되는 단계에, 대응되는 장치가,

클럭에 맞추어 대응되는 연산이 진행될 것이다.

[STEP 1]

STEP1 신호[A레지스터] and 출력 제어 클럭 신호(clk_e) and A레지스터 선택 코드[00~11]
TEP1 신호[ALU입력] and 입력 제어 클럭 신호[clk_s] and ALU 연산 코드 [1]

[STEP 2]
STEP2 신호[B레지스터] and 출력 제어 클럭 신호(clk_e) and B레지스터 선택 코드(00~11)
STEP2 ACC레지스터 신호 and 입력 제어 클럭 신호(clk_s) and [ALU 연산] 코드[1]
STEP2 OPcode 입력 신호 and OPcode (000~111) and [ALU 연산] 코드[1]

[STEP 3]
STEP 3 ACC레지스터 신호 and 출력 제어 클럭 신호(clk_e) and ALU 연산 코드[1]
STEP 3A레지스터 신호 and 입력 제어 클럭 신호(clk_s) and [피연산자_1] 레지스터 선택 코드

이를 회로로 구현하면 다음과 같다.

< IR : 1 101 00 01ADD R0, R1 >
: RA와 RB를 ADD연산 후 RA에 저장
: R0와 R1을 ADD 연산 후 R0에 저장

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

< 확대 (1) >
: 클럭과 스테퍼 신호 그리고 특정 이진수(명령어) 신호를
R0~R3 레지스터와 연결하여 명령어에 따라 레지스터 선택 

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

< 확대 (2) >
: 클럭과 스테퍼 신호 그리고 특정 이진수(명령어)의 OPcode 신호를
AND 연산하여 OPcode로 전달

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

< 확대 (3) >
: 클럭과 스테퍼 신호 그리고 특정 이진수(명령어)의 ALU 명령어 신호를
AND 연산하여 ALU 입력 제어기로 전달

※ 해당 이미지는 Logisim 프로그램을 통해 제작하였습니다.

이처럼 결국 제어장치가 명령어를 해석한다는 것은,

목적에 맞게 설계된 회로를

특정한 이진수 신호에 대응시킬 수 있는 디코더와 연결하여

사용자에게 회로와 대응된 이진수를 제공함으로써,

사용자가 명령어를 입력하면 그에 대응되는 신호를 활성화되어

해당 신호와 연결된 장치들이 클럭에 맞추어 동작하는 것이다.

 

 

이번 글은 요기서 마치며, 다음 주제는 제어장치를 구현하는 데 있어서

아직까지는 레지스터에 값을 직접 입력해 주어야 한다는 한계가 있는데

이를 어떻게 극복할 수 있을지

또, 뺄셈 연산과 나눗셈 연산과 같이 여러 명령어를 사용해야 하는데

그러한 값들을 어디에 저장하고, 어떻게 처리해야 할지 대해 탐구해 보겠다.


※ 해당 게시글은 주제를 탐구하면서 주관적인 생각을 정리 한 글입니다.

728x90