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

[컴퓨터][29] 입출력(I/O) 장치 : 키보드의 원리

core-basic 2024. 12. 14. 20:27
728x90

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


 

이전 글들을 통해 8BIT 컴퓨터를 구현하면서

컴퓨터가 어떻게 구성되어 있고, 각 장치들이

어떻게 동작하는지 구체적으로 이해할 수 있었다.

 

특히 스위치와 릴레이 회로를 통해 구현된 컴퓨터 장치들이

제공하는 이진수의 집합 : 이진수 코드를 통해

사용자들은 여러 스위치 회로를 열고 닫으며

컴퓨터에게 명령어를 입력하고,

같은 원리로 컴퓨터가 명령어를 처리한다는 점을 파악하였다.

 

[컴퓨터][27] 컴퓨터 완성 : Non-ALU 명령어 및 플래그 (데이터 명령어 / 분기 명령어 / 직접 분기 명

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

core-basic.tistory.com

이후 이진수 코드를 좀 더 쉽게 작성하고, 이해하기 위해

각 이진수 코드에 문자를 대응시킨 언어 체계인

"어셈블리어"가 등장했다. 

그리고 어셈블리어를 다시 컴퓨터가 처리할 수 있는

이진수(전기/전류)로 변환하는 과정을 "어셈블러"라고

부르는 것을 알 수 있었다.

 

이에 따라 초기에는 우선 종이와 펜으로

어셈블리어를 작성하면서 프로그래밍을 하고,

작성된 어셈블리어를 바탕으로 사람이 직접 이진수로 변환하여,

스위치를 통해 변환된 이진수를 컴퓨터 메모리에 직접 입력했다.

즉, 초기에는 수작업으로 프로그래밍하고, 어셈블러 과정을 진행했다.

 

이후 천공카드와 타자기 그리고, 천공카드 해독기가 도입되면서

프로그래밍 과정이 개선되었다.

아스키코드와 같이 특정 문자를 이진수에 대응시키는 코드 집합을

기반으로, 천공카드 타자기를 설계하여,

특정 키(문자)를 누르면 각 문자에 대응되는 이진수에 맞추어

'1'이면 천공카드를 뚫고,
'0'이면 천공카드를 뚫지 않는 

원리를 이용하여 수작업보다 빠르게 어셈블리어를 작성할 수 있었다.

뿐만 아니라, 해당 과정에서 명령어와 데이터를 구분하기 위해 

비트 추가하여  해당 비트가 뚫려있을 경우에는 명령어로 처리하고,

뚫려있지 않으면 데이터로 처리하는 형식을 이용하였다.

 

그리고 천공카드 해독기는 천공카드의 구멍 유무를 감지하여,

이진수를 메모리에 입력하거나, 명령어 코드로 변환하여 처리하였다.

이로써 수작업보다 빠르게 어셈블리어를 작성하고,

컴퓨터에 입력하는 것이 가능해졌다.

 

이후, 최초의 소프트웨어적인 어셈블러 프로그램이 개발되었다.

소프트웨어 어셈블러는 더 효율적인 명령어 변환을 가능하게 했으며,

이를 바탕으로 점차 더 발전된 어셈블러가 연쇄적으로 제작되었다.

 

[컴퓨터][28] 초기 어셈블리어와 어셈블러 구현 및 원리 (Assembly language, Assembler)

※ 해당 게시글은 주제를 탐구하면서 주관적인 생각을 정리 한 글입니다.이전 글들을 통해 ALU 명령어와 Non-ALU 명령어에 대해 알아보았다.그러면서 명령어가 무엇인지, 명령어는 어떻게

core-basic.tistory.com

그러면서, 키보드와 소프트웨어 어셈블러는

천공카드와 타자기, 천공카드 해독기의 역할을 대체하게 되었다.

 

키보드는 문자 및 데이터 모드/명령어 모드 등을

입력하는 과정을 단순화시켰으며,

어셈블러 프로그램은 키보드로부터 입력된 문자열이 명령어인지,

데이터인지 구별하고, 메모리 회로에 입력하였다.

 

그리고 이어서 도입된 모니터는 입력된 데이터와 명령어를

시각적으로 확인할 수 있도록 해주어

프로그래밍 과정을 더욱 편리하게 만들어주었다.

 

그러면 키보드와 모니터 중

우선 키보드가 어떠한 원리로 동작하는지 탐구해 보겠다.

 

< 입출력 장치(I/O) : 키보드의 원리 >

 


< 입력장치 : 키보드의 원리 >

" 키보드는 어떠한 원리로 동작하는가? "

" 키보드의 키를 누르면 어떤 일 발생하는가? "

 

초기의 키보드는 각 키마다 문자 및 숫자등을 대응시켰고,

각 문자 및 수자는 아스키코드 등 이진수 코드에 대응시켜,

특정 키(문자)를 누르면, 해당 문자에 대응되는 이진수 코드가

메모리 회로에 입력되도록 하는 원리를 따랐다.

 

이때, 키보드와 같이 외부장치로부터

데이터가 컴퓨터(CPU/RAM 등)에 전달되는 과정을 Input(입력),

반대로 컴퓨터로부터

데이터가 키보드에 전달되는 과정을 Output(출력)이라고 한다.

 

그래서 입출력 행위를 I/O라고 부르기도 하며,

입출력의 주체/기준은 컴퓨터(CPU/RAM 등)이다.

 

" 어떻게 회로를 설계해야 위와 같은 기능을 실현시킬 수 있을까? "

" 더 나아가 이전 글들을 통해 구현한 8BIT 컴퓨터와 결합할 수 있을까? "

 

위의 기능을 구현하고자 하였을 때 필자가 생각한

가장 간단한 절차/ 가장 먼저 생각나는 절차는

다음과 같았다.

[1 단계]
키를 누르면 해당 키에 대응되는 문자의 아스키코드에 따라

여러 스위치 중 일부 스위치만 눌리도록 하는 원리를 이용해

아스키코드 신호를 생성한다.

 

[2 단계]
활성화된 신호를 메모리 회로에 전송한다.

 

그래서 우선 Logisim 프로그램을 통해 [1 단계]를 간단한 회로로 

구현해 보면 다음과 같다.

ex) A = 0x41 = 65 = 0100 0001

 

(1) 키(버튼)와 NOT, AND 게이트를 이용한 회로

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

 

(2) 키(버튼)와 Tri-state buffer 소자를 이용한 회로

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

 

이어서 [2 단계]를 구현하는 데 있어서는 여러 가지 문제가 발생하였다.

그중 필자가 가장 먼저 떠오른 문제들은 다음과 같았다.

(문제 1) 생성된 아스키코드를 어떤 메모리 회로에 저장할지

(문제 2) 생성된 아스키코드를 언제 메모리 회로에 저장할지

(문제 3) 생성된 아스키코드를 어떻게 메모리 회로에 저장할지

등등..

 

위와 같은 문제들을 해결하기 위해서는 키보드와 관련된

명령어가 필요하다고 느꼈다.

명령어는 주어진 여러 장치들 중 필요한 장치들 선택하여

클럭과 스테퍼 신호에 따라 서로 데이터를 송수신할 수 있도록

해주는 이진수 코드로,

이를 이용하면 키보드에 의해 생성된 아스키코드가,

특정 레지스터 장치에 저장할 수 있도록 할 수 있을 뿐만 아니라, 

추가적으로 키를 눌렀을 때 생성되는 아스키코드를

임시 키보드 레지스터를 추가해 저장한다면,

클럭과 스테퍼를 통해 특정 시점에서만

임시 키보드 레지스터에 저장되어 있는 아스키코드를 가져와

CPU에 있는 특정 레지스터에 저장할 수 있다.


< I/O 명령어 >

그래서 앞서 구현한 컴퓨터에서 Non-ALU 명령어 중

비교적 쓸모가 없는 [0][111] [XXXX] : NOP 명령어 대신에

키보드와 같이 외부장치와 관련된 I/O 명령어를 추가한다.

※ 만약 레지스터와 ALU, 버스(BUS) 크기 등, 컴퓨터를 16BIT로 확장한다면
더 다양하고, 복잡한 명령어를 처리할 수 있다.  

I/O 명령어 : [0] [111] [I/O] [D/A] [RB]

[0] [111] [0] ~ [1] [0] ~ [1] [00] ~ [11]
[0] : Non-ALU [111] : I/O 명령어  OPcode [0] : Input
[1] : Output
[0] : Data
[1] : Address
[00] : R0
[01] : R1
[10] : R2
[11] : R3

 

I/O 명령어에서 하위
 3번째 비트(Data/Address)
4번째 비트(Input/Output)

에 대해 설명하면

앞서 언급하였듯이 I/O 외부장치는 키보드뿐만 아니라,

모니터, 스피커, 마우스 등 여러 외부장치가 존재한다.

따라서 입력 장치인 키보드만 고려하는 명령어가 아닌

다른 모든 입출력 장치들 까지 고려하는,

범용성 있는 명령어 구현하기 위해서는

각 장치마다 특정 이진수(주소)를 가질 수 있도록 설계하여,

CPU가 어떤 장치와 값을 주고받을지 선택할 수 있도록 한다.

 

이를 통해 CPU는 특정 장치와 통신 채널을 연결 및 유지할 수 있도록 한다.

즉, CPU는 하나의 외부장치만 선택하여 안정적으로 통신할 수 있도록 한다.

 

이에 따라 하위 3번째 비트는 CPU와 외부장치가 주고받는 값이

주소인지, 데이터인지 구분할 수 있도록 한다.

하위 4번째 비트는 CPU와 외부 장치가 값을 주고받을 때,

CPU 기준 해당 값이 입력되는 값인지, 출력되는 값인지

구분할 수 있도록 한다.

 

이에 따라 외부 I/O 장치는 다음과 같은 전선들을 통해

CPU와 연결 및 통신하게 된다.

(1) BUS : CPU와 외부 I/O장치가 주고받는 데이터 또는 주소
(2) Input/Output : CPU를 기준으로 하였을 때 송수신 값이 입력값인지, 출력값인지 설정
(3) Data/Address : 송수신 값이 데이터(Data)인지, 주소(Address)인지 결정
(4) I/O clk_s : I/O 전용 클럭 신호로, CPU 기준 출력, I/O장치 기준 입력
(5) I/O clk_e : I/O 전용 클럭 신호로, CPU 기준 입력, I/O장치 기준 출력

그리고 I/O 명령어에 대해 RB 레지스터의 경우의 수를 제외한

모든 경우의 수를 정리하면 다음과 같다.

0111 00RB : I/O, Input, Data, RB : I/O 장치로부터 RB로 데이터 수신
0111 01RB : I/O, Input, Address, RB : I/O 장치로부터 RB로 주소 수신
0111 10RB : I/O, Output, Data, RB : RB로부터 I/O 장치로 데이터 전송
0111 11RB : I/O, Output, Address, RB :RB로부터 I/O 장치로 주소 전송

이처럼 외부 장치마다 특정 이진수(주소)를 가지도록 설계하고,

해당 주소를 이용해 CPU와 외부장치를 연결하고,

CPU가 전달하는 값을 받거나,

CPU로부터 값을 전달하는 등

외부장치에서 신호를 처리하는 시스템을 인터페이스 또는 어댑터라고 한다.


< 키보드와 키보드 인터페이스(어댑터)  구현 >

이에 따라 모든 외부장치는 각기 다른 주소를 가지는

인터페이스(어댑터)를 설계해야 한다.

 

그러면 위의 내용을 기반으로 키보드와 키보드 인터페이스(어댑터)를

간단하게 설계하면 다음과 같다.

※ 키보드 주소 : 0000 0001
※ 입력으로는 BUS(8bit 값), I/O clk_e(1bit), I/O clk_s (1bit),
Input/Output (1bit) , Data/Address (1bit) 등의 신호가 있다.
※ 출력으로는 키를 눌렀을 때 발생하는 아스키코드 (8bit)이다.

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

 

해당 회로의 기능을 좀 더 세부적으로 살펴보면 다음과 같다.

(1) 사용자가 키를 누렀을 때 "임시 키보드 레지스터 : KeyR"에 저장한다.

ex) A = 65 = 0x41 = 0100 0001, B = 66 = 0x42 = 0100 0010

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

 

(2) CPU에서 RB에 저장된 값(주소)을
모든 I/O 장치의 인터페이스(어댑터)로 보낸다.

ex) 0111 11RB = I/O, Output, Address, RB (RB:0000 0001)

※ 각 장치의 인터페이스(어댑터)는 설계 구조에 따라 각기 다른 주소를 가지며 해당 주소를 값으로 받으면 채널 연결이 활성화(1) 되도록 설계되어 있다.
※ RB:0000 0001을 키보드의 주소로 설계하였으며, 이에 따라 키보드와 통신 채널이 활성화된다. (채널 연결 여부 = 1)
※ 채널 연결 여부 : 0000 0001 && I/O clk_s && Output && Address

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

(3) 이후 CPU는 임시 키보드 레지스터에 저장되어 있는 아스키코드를
RB로 가져온다. (외부 I/O 장치가 출력할 수 도록 유도한다.)

ex) 0111 00RB = I/O, Input, Data, RB

※ KeyR 출력 제어 신호 : 채널 연결 여부[1] && I/O clk_e && Data

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

(4) 이후, 채널 연결이 종료될 때까지 데이터를 주고받을 수 있다

※ 이때 연결 종료는 0111 11RB = Out Address RB(RB:0000 0000) 명령어를 통해 연결을 종료한다.
※ 즉, 각 장치의 주소를 배정 및 설계할 때 0000 0000은 아무 장치도 연결하지 않음을 뜻하므로 제외한다.

(5) 그리고 연결이 종료되는 명령어가 실행되어
키보드 인터페이스(어댑터)가 0000 0000이라는 주소를 받을 때
임시 키보드 레지스터(KeyR)는 0으로 초기화되도록 설계하였다.

ex) XOR RB, RB → 0111 11RB = I/O, Output, Address, RB(RB:0000 0000)

※ 만약 0으로 초기화시키지 않으면 후에 CPU가 임시 키보드 레지스터에 값이 있는지 확인할 때 키를 누르지 않았음에도, 이전 값이 그대로 유지되어 해당 값을 가져오는 문제가 발생할 수 있기 때문이다.

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


< 컴퓨터와 키보드 결합 >

이어서 이전 글들을 통해 구현한 8BIT 컴퓨터와

앞서 구현한 키보드를 결합한 결과는 다음과 같다.

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

결합과정을 STEP에 따라 좀 더 세부적으로 살펴보면 다음과 같다.

 

[STEP 4]

RB 출력 제어 신호
: (([0] Non-ALU && [111] OPcode) && [1] Output(:IR [3]) && STEP 4 || 다른 ALU/Non-ALU 연산) && clk_e

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

 

I/O clk_s 신호
: ([0] Non-ALU && [111] OPcode) && [1] Output(:IR [3]) && STEP 4) && clk_s

※ 외부 I/O장치에 입력클럭신호를 제공함으로써, 특정 타이밍에만 안정적으로 CPU(RB)가 출력한 값을 외부 I/O장치가 입력받을 수 있도록 한다.)

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

 

Input/Ouput 신호
: IR [3]

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

 

Data/Address 신호
: IR [4]

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

[STEP 5]

I/O clk_e
: : ([0] Non-ALU && [111] OPcode) && [0] Input(:NOT(IR [3])) && STEP 5) && clk_e

※ 외부 I/O장치에 출력클럭신호를 제공함으로써, 특정 타이밍에만 안정적으로 외부 I/O장치가 값을 출력하여 CPU(RB)가 입력받을 수 있도록 한다.

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

 

RB 입력 제어 신호
: (([0] Non-ALU && [111] OPcode) && [0] Input(:NOT(IR [3])) && STEP 5 || 다른 ALU/Non-ALU 연산) && clk_s

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

 

Input/Ouput 신호
: IR [3]

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

 

Data/Address 신호
: IR [4]

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

 

다시,

키보드 입력이 처리되는 과정을 좀 더 세분화하여 정리하면 다음과 같다.

[1단계]

키를 누르면 해당 키에 대응되는 문자의 아스키코드에 따라 여러 스위치 중

일부 스위치만 눌리도록 하는 원리를 이용하여 아스키코드 신호를 생성한다.

 

[2단계]

임시 키보드 레지스터에 아스키코드를 저장한다.

 

[3단계]

주기적으로 CPU에서 키보드 인터페이스(어댑터)와 연결하여

값을 가져와 확인한 후 연결을 해제한다.

※연결을 해제하는 명령어를 진행할 때 임시 키보드 레지스터는 0으로 초기화하도록 한다

(1) DATA R0, XX [0000 0001을 가지고 있는 8BIT RAM 주소]

(2) Output Address, R0

(3) Input Data, R1

(4) XOR R0, R0

(5) Output Address, R0

 

[4단계]

이후 추가적인 명령어를 통해 레지스터에 저장되어 있는 아스키코드를

지정된 RAM에 저장(SOTRE)한다.

 

 

이렇게 해서 키보드의 원리를 살펴보았지만,

실질적으로 CPU에서 주기적으로 키보드의 상태를 확인하여

입력값을 처리하는 것은 비효율적이다.

따라서

현재 대부분의 시스템은 오히려 반대로

키보드의 입력이 발생하였을 때 인터럽트라는 신호를 생성하여

CPU에게 전달하는 방식을 사용한다.

그리고 CPU 레지스터를 경유하지 않고,

곧바로 RAM에 저장할 수 있도록 추가적인 장치를 설계하여

CPU의 불필요한 작업을 줄이고, 효율적으로 키보드의 입력을 처리한다.

 

 

다음 주제는 이어서 모니터의 원리에 대해 탐구해 보겠다.


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

728x90