반응형

 

입출력장치는 컴퓨터 외부와 연결되어 컴퓨터 내부와 정보를 주고받을 수 있는 장치이다. 예) 마우스, 프린터, 헤드폰, 모니터 등등

그러면 입출력장치들이 어떻게 컴퓨터 내부와 정보를 주고받을까?

참고: 여기서 입출력장치는 보조기억장치도 포함한다.
보조기억장치는 입출력장치의 한 종류로 볼 수 있다. 다만 보조기억장치는 메모리를 보조한다는 특별한 역할을 수행하는 입출력장치이다.

 

장치 컨트롤러와 장치 드라이버

입출력장치는 CPU, 메모리보다 다루기 더 까다롭다. 왜일까?

 

1. 입출력장치에는 종류가 너무나도 많다.

  • 키보드, 모니터, USB 메모리, SSD, 마우스 등 매우 많다.
  • 장치가 다양하면 장치마다 속도, 데이터 전송 형식 등도 다양하다.
    • 따라서, 다양한 입출력장치와 정보를 주고받는 방식을 규격화하기 어렵다.
    • 예시) CPU와 메모리는 한국어를 사용하는데, 프린터는 영어를 사용하는 상황과 같다.

 

2. 일반적으로 CPU와 메모리의 데이터 전송률은 높지만 입출력장치의 데이터 전송률은 낮다.

  • 전송률이란 데이터를 얼마나 빨리 교환할 수 있는지를 나타내는 지표이다.
  • CPU와 메모리처럼 전송률이 높은 장치는 1초에 수많은 데이터를 주고받을 수 있다.
  • 하지만, 키보드나 마우스와 같이 상대적으로 전송률이 낮은 장치는 1초에 데이터를 조금씩만 주고받을 수 있다.
  • 이런 전송률의 차이는 CPU와 메모리, 입출력장치 간의 통신을 어렵게 한다.
    • 예시) 1초에 1,000마디를 내뱉는 사람과 1초에 한 마디를 내뱉는 사람끼리 대화한다고 생각해 보자.
참고: 물론 어떤 입출력장치는 CPU나 메모리보다 전송률이 높은 경우가 있다. 하지만 결과적으로 CPU나 메모리와 전송률이 비슷하지 않기 때문에 같은 어려움을 겪는다.

이러한 이유 때문에 등장한 것이 바로 장치 컨트롤러이다.

 

장치 컨트롤러 (device controller)

장치 컨트롤러. 장치 컨트롤러는 하드웨어다.
  • 입출력장치는 컴퓨터에 직접 연결되지 않고, 장치 컨트롤러라는 하드웨어를 통해 연결된다.
  • 장치 컨트롤러는 입출력 제어기(I/O controller), 입출력 모듈(I/O module) 등으로 불리기도 한다.
  • 모든 입출력장치는 각자의 장치 컨트롤러를 통해 컴퓨터 내부와 정보를 주고받는다.
  • 장치 컨트롤러는 하나 이상의 입출력장치와 연결되어 있다.
    • 예시) 하드 디스크 또한 장치 컨트롤러가 있다.

 

장치 컨트롤러의 역할

장치 컨트롤러의 역할을 크게 3가지로 나눌 수 있다.

  • CPU와 입출력장치 간의 통신을 중개한다.
    • 다양한 입출력장치와 정보를 주고받는 방식을 규격화하기 어렵다고 했다.
    • 이 문제를 장치 컨트롤러가 일종의 번역가 역할을 함으로써 해결할 수 있다.
  • 입출력장치의 오류를 검출한다.
    • 자신과 연결된 입출력장치에 문제는 없는지 오류를 검출한다.
  • 데이터 버퍼링 기능을 제공한다.
    • 버퍼링이란 전송률이 높은 장치와 낮은 장치 사이에 주고받는 데이터를 '버퍼'라는 임시 저장 공간에 저장하여 전송률을 비슷하게 맞추는 방법이다.
    • 쉽게 말해, 버퍼에 데이터를 조금씩 모았다가 한꺼번에 내보내거나, 데이터를 한 번에 많이 받아 조금씩 내보내는 방법이라고 보면 된다.
    • 즉, 일반적으로 전송률이 높은 CPU와 전송률이 낮은 입출력장치와의 전송률 차이를 데이터 버퍼링으로 완화한다.
버퍼링의 예시

 

 

장치 컨트롤러의 구조

장치 컨트롤러의 간략화된 내부 구조
  • 장치 컨트롤러는 입출력 버스에 연결되어 정보를 주고받게 된다.
  • 주고받는 정보에는 크게 3가지가 존재한다.
    • 데이터, 데이터 레지스터에 담기게 된다.
    • 상태, 상태 레지스터에 담기게 된다.
    • 제어, 제어 레지스터에 담기게 된다.
참고: 상태 레지스터와 제어 레지스터는 하나의 레지스터(상태/제어 레지스터)로 사용되기도 한다. 

 

데이터 레지스터

  • 데이터 레지스터는 CPU와 입출력장치 사이에 주고받을 데이터가 담기는 레지스터이다.
  • 데이터 레지스터가 버퍼 역할을 한다.
  • 참고: 주고받는 데이터가 많은 입출력장치에서는 레지스터 대신 RAM을 사용하기도 한다.

 

상태 레지스터

  • 상태 레지스터는 상태 정보가 저장된다. 아래와 같은 정보들을 말한다.
    • 입출력장치가 입출력 작업을 할 준비가 되었는지
    • 입출력 작업이 완료되었는지
    • 입출력장치에 오류는 없는지 

 

제어 레지스터

  • 제어 레지스터는 입출력장치가 수행할 내용에 대한 제어 정보와 명령을 저장한다.

 

이 세 가지 레지스터들에 담긴 값들은 버스를 타고 CPU나 다른 입출력장치로 전달되기도 하고, 장치 컨트롤러에 연결된 입출력장치로 전달된다.

 

장치 드라이버

새로운 장치를 컴퓨터에 연결하려면 장치 드라이버를 설치해야 한다.

  • 장치 드라이버는 장치 컨트롤러의 동작을 감지하고 제어함으로써 장치 컨트롤러가 컴퓨터 내부와 정보를 주고받을 수 있게 하는 프로그램이다.
  • 즉, 장치 컨트롤러가 입출력장치를 연결하기 위한 하드웨어적인 통로라면, 장치 드라이버는 입출력장치를 연결하기 위한 소프트웨어적 통로이다.
  • 프린터기를 컴퓨터에 연결했다고 가정하자.
  • CPU가 프린터기의 장치 컨트롤러를 어떻게 동작하는지 알지 못하면 연결이 되었다고 해도 정보를 주고받을 수 없다.
  • 장치 드라이버를 통해 어떻게 동작시키는지를 CPU가 알 수 있게 된다.

 

장치 드라이버가 설치되어 있지 않다면 해당 입출력장치를 사용할 수 없다.
  • 운영체제가 연결된 장치의 드라이버를 인식하고 실행할 수 있다면 컴퓨터 내부와 정보를 주고받을 수 있다.
  • 반대로 운영체제가 연결된 장치의 드라이버를 인식하거나 실행할 수 없다면 컴퓨터 내부와 정보를 주고받을 수 없다.
참고: 장치 드라이버를 인식하고 실행하는 주체는 운영체제이다. 즉, 장치 드라이버를 인식하고 실행할 수 있다면 그 장치는 컴퓨터 내부와 정보를 주고받을 수 있다. 장치 드라이버는 운영체제가 기본으로 제공하는 것도 있지만, 장치 제작자가 따로 제공하기도 한다.

 

다양한 입출력방법

입출력 작업을 수행하기 위해서는 CPU와 장치 컨트롤러가 정보를 주고받아야 한다. 장치 컨트롤러는 CPU와 어떻게 정보를 주고받을까?

크게 3가지 입출력 방식이 존재한다.

  • 프로그램 입출력
  • 인터럽트 기반 입출력
  • DMA 입출력

 

프로그램 입출력(programmed I/O)

  • 프로그램 입출력은 프로그램 속 명령어로 입출력 장치를 제어하는 방법이다.
    • 입출력장치에 연결된 장치 컨트롤러를 프로그램 속 명령어로 제어하는 방법
    • 즉, 입출력 명령어로써 장치 컨트롤러와 상호작용하는 방법이다.

 

메모리에 저장된 정보를 하드 디스크에 백업하는 과정을 생각해 보자.

즉, 하드 디스크에 새로운 정보를 쓰기 하는 작업이다. 이때, 프로그램 입출력을 통해 어떻게 상호작용을 할까?

  • 1. CPU는 하드 디스크 컨트롤러의 제어 레지스터에 쓰기 명령을 보낸다.
  • 2. 하드 디스크 컨트롤러는 하드 디스크 상태를 확인한다. 하드 디스크가 준비된 상태라면 하드 디스크 컨트롤러는 상태 레지스터에 준비되었다고 표시한다.
  • 3-1. CPU는 상태 레지스터를 주기적으로 읽어보며 하드 디스크의 준비 여부를 확인한다.
  • 3-2. 하드 디스크가 준비되었다면, 백업할 메모리의 정보를 데이터 레지스터에 쓴다.
  • 만약 아직 백업 작업, 쓰기 작업이 끝나지 않았다면 1번부터 반복하고, 쓰기가 끝났다면 작업을 종료한다.

 

프로그램 입출력 방식에서의 입출력 작업은 CPU가 장치 컨트롤러의 레지스터 값을 읽고 씀으로써 이루어진다.

근데 입출력장치의 종류가 너무나도 다양해 입출력장치와 정보를 주고받는 방식을 규격화하기 어렵다고 했다.

그렇다면 CPU는 입출력장치들의 주소 즉, CPU는 장치 컨트롤러의 레지스터 값들을 어떻게 아는 걸까?

즉 아래와 같은 명령어들은 어떻게 명령어로 표현되고, 어떻게 메모리에 저장될까?

  • 예시 1) 프린터 컨트롤러의 상태 레지스터를 읽어라.
  • 예시 2) 프린터 컨트롤러의 데이터 레지스터에 100을 써라

 

CPU가 장치 컨트롤러의 레지스터 값들을 아는 방법으로는 크게 두 가지 방식이 존재한다.

  • 메모리 맵 입출력(memory-mapped I/O)
  • 고립형 입출력(isolated I/O

 

프로그램 입출력 - 메모리 맵 입출력(memory-mapped I/O)

  • 메모리 맵 입출력은 메모리에 접근하기 위한 주소 공간과 입출력장치에 접근하기 위한 주소 공간을 하나의 주소 공간으로 간주하는 방법이다.
  • 1,024개의 주소를 표현할 수 있는 컴퓨터가 있다고 하면, 512개는 메모리 주소를, 512개는 장치 컨트롤러의 레지스터를 표현하는 데  사용한다.

 

다음 예시를 통해 메모리 맵 입출력을 이해해 보자. 

주소 공간 일부를 아래와 같이 약속했다고 가정하자.

  • 516번지: 프린터 컨트롤러의 데이터 레지스터
  • 517번지: 프린터 컨트롤러의 상태 레지스터
  • 518번지: 하드 디스크 컨트롤러의 데이터 레지스터
  • 519번지: 하드 디스크 컨트롤러의 상태 레지스터

'517번지를 읽어 들여라' 명령어로 프린터 컨트롤러의 상태를 읽을 수 있다.

'518번지에 a를 써라' 명령어로 하드 디스크에 a를 쓸 수 있다.

위 두 명령어들을 보면, 두 명령어들은 메모리에 접근하는 명령어와 똑같이 생겼다는 것을 알 수 있다.

다시 말해 메모리 접근 명령어와 입출력장치 접근 명령어가 똑같이 생겼다는 뜻이다. 메모리에 접근하기 위한 주소 공간과 입출력장치에 접근하기 위한 주소 공간을 하나의 주소 공간으로 간주했기 때문이다.

 

프로그램 입출력 - 고립형 입출력(isolated I/O)

메모리 읽기/쓰기 선과 입출력장치 읽기/쓰기 선이 따로 존재한다.
1,024개를 메모리를 위해서도 사용할 수 있고, 입출력장치를 위해서 사용할 수 있다.
  • 고립형 입출력은 메모리를 위한 주소 공간과 입출력장치를 위한 주소 공간을 분리하는 방법이다. (메모리 맵 입출력과 반대)
  • 1,024개의 주소 공간을 가진 컴퓨터가 있다고 가정해 보자.
  • 메모리 읽기/쓰기 선과 입출력장치 읽기/쓰기 선이 따로 있으면 메모리에도 1,024개의 주소 공간을 활용하고, 입출력장치도 1,024개의 주소 공간을 활용할 수 있다.
    • CPU가 메모리 읽기/쓰기 선이 활성화되는 명령어를 실행하면 메모리에 접근한다.
    • CPU가 입출력장치 읽기/쓰기 선이 활성화되는 명령어를 실행하면 장치 컨트롤러에 접근한다.
  • 고립형 입출력 방식에서 CPU는 입출력장치에 접근하기 위해 메모리에 접근하는 명령어와는 다른 (입출력 읽기/쓰기 선을 활성화시키는) 입출력 전용 명령어를 사용한다.

 

메모리 맵 입출력 vs 고립형 입출력

프로그램 입출력 방식에는 크게 메모리 맵 입출력과 고립형 입출력 두 가지 방식이 있다.

 

인터럽트 기반 입출력

  • 하드웨어 인터럽트는 장치 컨트롤러에 의해 발생한다.
  • CPU는 장치 컨트롤러에 입출력작업을 명령하고, 장치 컨트롤러가 입출력장치를 제어하며 입출력을 수행하는 동안 CPU는 다른 일을 할 수 있다.
  • 장치컨트롤러가 입출력 작업을 끝내면 CPU에게 인터럽트 신청을 보낸다. 
  • CPU는 하던 일을 잠시 백업하고 인터럽트 서비스 루틴을 실행한다.
참고: CPU는 주기적으로 장치 컨트롤러의 상태 레지스터를 확인하며 입출력장치의 상태를 확인한다고 했다. 폴링 이처럼 입출력장치의 상태는 어떤지, 처리할 데이터가 있는지 주기적으로 확인하는 방식이다. 폴링 방식은 인터럽트 방식보다 CPU 부담이 더 크다. 왜냐하면 인터럽트를 활용하면 CPU가 인터럽트 요청을 받을 때까지 다른 일을 할 수 있기 때문이다.

 

입출력장치가 많을 때를 생각해 보자.

컴퓨터를 예시로 들면 다양한 입출력장치가 연결되어 있다. 키보드, 마우스, 모니터, 스피커 등등...

이 말은 컴퓨터 속 CPU가 동시다발적으로 발생하는 키보드, 마우스, 모니터, 스피커 인터럽트를 모두 처리해야 한다는 뜻이다.

여러 입출력장치에서 인터럽트가 동시에 발생하는 경우에는 인터럽트를 어떻게 처리해야 할까?

 

인터럽트가 발생한 순서대로 인터럽트를 처리하는 방법이 있다.

발생 순서대로 처리한다.
  • CPU가 플래그 레지스터 속 인터럽트 비트를 비활성한 채 인터럽트를 처리하는 경우, 다른 입출력장치에 의한 하드웨어 인터럽트를 받아들이지 않기 때문에 CPU는 하드웨어 인터럽트를 순차적으로 처리한다.

 

하지만 모든 인터럽트를 순차적으로 해결할 수는 없다. 왜냐하면 인터럽트 중에서도 더 빨리 처리해야 하는, 우선순위가 높은  인터럽트가 있기 때문이다. 즉, CPU는 인터럽트 간에 우선순위를 고려해 우선순위가 높은 인터럽트 순으로 여러 인터럽트를 처리할 수 있다.

우선순위를 고려한다.
  • 플래그 레지스터 속 인터럽트 비트가 활성화되어 있는 경우, 인터럽트 비트를 비활성화해도 무시할 수 없는 인터럽트 NMI(Non-Maskable Interrupt)가 발생한 경우 CPU는 우선순위가 높은 인터럽트부터 처리한다. (우선순위 반영)

 

우선순위를 반영해 다중 인터럽트를 처리하는 방법으로

많은 컴퓨터에서는 프로그래머블 인터럽트 컨트롤러, PIC(Programmable Interrupt Controller) 하드웨어를 사용한다.

PIC
  • PIC는 여러 장치 컨트롤러에 연결되어 장치 컨트롤러에서 보낸 하드웨어 인터럽트 요청들의 우선순위를 판단한다.
  • 그 후 CPU에게 지금 처리해야 할 하드웨어 인터럽트가 무엇인지 알려준다
  • 참고: NMI 우선순위까지는 판단하지 않는다. NMI의 우선순위가 가장 높기 때문이다.

 

  • PIC에는 여러 핀이 존재하는데 각 핀에는 CPU에 하드웨어 인터럽트 요청을 보낼 수 있는 약속된 하드웨어가 연결되어 있다.
    • 첫 번째 핀은 키보드 인터럽트를 받아들이는 핀, 두 번째 핀은 마우스 인터럽트를 받아들이는 핀 등등...
  • PIC에 연결된 장치 컨트롤러들이 동시에 하드웨어 인터럽트 요청을 보내면, PIC는 장치컨트롤러와 CPU 사이에서 이들의 우선순위를 판단하여 CPU에게 가장 먼저 처리할 인터럽트를 알려준다.
여러 개의 PIC를 사용하는 경우가 더 많다.
  • 더 많고 복잡한 장치들의 인터럽트를 관리하기 위해 PIC를 두 개 이상 계층적으로 구성한다.

 

좀 더 정확한 PIC의 다중 인터럽트 처리 과정

  1. PIC가 장치 컨트롤러에서 인터럽트 요청신호들을 받아들인다.
  2. PIC는 인터럽트 우선순위를 판단한 뒤 CPU에 처리해야 할 인터럽트 요청 신호를 보낸다.
  3. CPU는 PIC에 인터럽트 확인 신호를 보낸다.
  4. PIC는 데이터 버스를 통해 CPU에 인터럽트 벡터를 보낸다.
  5. CPU는 인터럽트 벡터를 통해 인터럽트 요청의 주체를 알게 되고, 해당 장치의 인터럽트 서비스 루틴을 실행한다.

 

DMA 입출력

프로그램 기반 입출력과 인터럽트 기반 입출력의 공통점은 뭘까?

바로 입출력장치와 메모리 간의 데이터 이동은 CPU가 주도하고 이동하는 데이터도 반드시 CPU를 거친다는 것이다.

입출력장치 데이터를 메모리에 저장하는 경우를 생각해 보자

입출력장치 데이터를 메모리에 저장하는 경우
  • 1. CPU는 장치 컨트롤러에서 입출력장치 데이터, 데이터 레지스터에 저장되어 있는 값을 하나씩 읽어 CPU의 레지스터에 적재한다.
  • 2. CPU의 레지스터, 적재한 데이터를 메모리 쓰기 명령어를 통해 메모리에 저장한다.

 

메모리 속 데이터를 입출력장치에 내보내는 경우도 마찬가지이다.

메모리 속 데이터를 입출력장치에 내보내는 경우
  • 1. CPU는 메모리에서 데이터를 하나씩 읽어 레지스터에 적재한다.
  • 2. 적재한 데이터를 하나씩 입출력장치, 장치 컨트롤러의 레지스터에 내보낸다.

 

입출력장치와 메모리 사이에 전송되는 모든 데이터가 반드시 CPU를 거쳐야 한다면 가뜩이나 바쁜 CPU는 입출력장치를 위한 연산 때문에 시간을 뺏기게 된다. 가뜩이나 바쁜 CPU인데 만약 하드 디스크 백업과 같이 대용량 데이터를 옮긴다면 CPU 부담이 더욱 커지게 된다.

이러한 문제를 해결하기 위해 DMA가 등장하였다.

 

DMA(Direct Memory Access)

  • DMA는 입출력장치와 메모리가 CPU를 거치지 않고도 상포작용할 수 있는 입출력 방식이다. 즉, CPU를 거치지 않고 입출력장치가 메모리에 직접적으로 접근하는 기능이다.
  • DMA 입출력을 하기 위해서는 시스템 버스에 연결된 DMA 컨트롤러라는 하드웨어가 필요하다.

 

DMA 입출력 과정

  • 1. CPU는 DMA 컨트롤러에 입출력장치의 주소, 수행할 연산(읽기/쓰기), 읽거나 쓸 메모리의 주소 등과 같은 정보로 입출력 작업을 명령한다.
  • 2. DMA 컨트롤러는 CPU 대신 장치 컨트롤러와 상호작용하며 입출력 작업을 수행한다. 이때 DMA 컨트롤러는 필요한 경우 메모리에 직접 접근해 정보를 읽거나 쓴다.
  • 3. 입출력 작업이 끝나면 DMA 컨트롤러는 CPU에 인터럽트를 걸어 작업이 끝났음을 알린다.

 

입출력장치와 메모리 사이에 주고받을 데이터는 CPU를 거치지 않는다는 것을 확인할 수 있다.

CPU는 DMA 컨트롤러에게 입출력 작업 명령을 내리고, 인터럽트만 받으면 되기 때문에 작업 무담을 훨씬 줄일 수 있다.

즉, CPU는 오로지 입출력의 시작과 끝에만 관여하면 된다.

 

하지만 DMA 컨트롤러는 시스템 버스로 메모리에 직접 접근 가능하지만, 시스템 버스는 공동 자원이기 때문에 동시 사용이 불가능하다.

즉, CPU가 시스템 버스를 사용할 때 DMA 컨트롤러는 시스템 버스를 사용할 수 없고, DMA 컨트롤러가 시스템 버스를 사용할 때는 CPU가 시스템 버스를 사용할 수 없다는 뜻이다.

따라서 DMA는 다음과 같은 방식으로 시스템 버스를 사용한다.

DMA의 시스템 버스 이용 방법
  • 1. DMA 컨트롤러는 CPU가 시스템 버스를 이용하지 않을 때마다 조금씩 시스템 버스를 이용한다.
  • 2. CPU가 일시적으로 시스템 버스를 이용하지 않도록 허락을 구하고 시스템 버스를 집중적으로 이용한다.
  • CPU 입장에서는 버스에 접근하는 주기를 도둑맞는 기분이 들 거다. 따라서 DMA의 시스템 버스 이용을 사이클 스틸링(cycle stealing)이라고 한다.

 

입출력 버스

장치 컨트롤러가 정말 많은데 시스템 버스와 직접적으로 연결되어 있어도 괜찮을까?

괜찮지 않다. 왜냐하면 DMA를 하는 과정에서 DMA 컨트롤러는 불필요하게 시스템 버스를 두 번씩 이용하게 된다.

  • 1. 메모리에서 DMA 컨트롤러로 데이터를 가져오기 위해 시스템 버스를 한 번 사용한다. (읽기)
  • 2. DMA 컨트롤러의 데이터를 장치 컨트롤러로 옮기기 위해 시스템 버스를 또 한 번 사용한다. (쓰기)

 

시스템 버스는 공용 자원이기 때문에 DMA를 위해 시스템 버스를 너무 자주 사용하면 그만큼 CPU가 시스템 버스를 이용하지 못한다.

이러한 문제를 해결하기 위해 DMA 컨트롤러와 장치 컨트롤러들을 입출력 버스(input/output bus)라는 별도의 버스에 연결하여 해결할 수 있다.

입출력 버스에 연결한다.
  • DMA 컨트롤러와 장치 컨트롤러가 서로 데이터를 전송할 때 시스템 버스를 이용할 필요가 없어 시스템 사용 빈도를 줄일 수 있다.
  • 현대 대부분 컴퓨터에는 입출력 버스가 있다. 즉 대부분의 입출력장치는 시스템 버스가 아닌 입출력 버스와 연결된다.
  • 입출력 버스는 여러 종류가 있는데 대표적으로 PCI(Peripheral Component Interconnect) 버스, PCI Express (PCIe) 버스 등이 있다.
슬롯들을 확인할 수 있다.
  • 여러 입출력장치들을 PCIe 버스와 연결해 주는 통로인 PCIe 슬롯이다.
  • 슬롯 -> 입출력 버스 -> 시스템 버스
참고: DMA 방식이 더욱더 발전해서 입출력 전용 CPU가 만들어졌는데 이를 입출력 프로세서 또는 입출력 채널이라 부른다.
 
 
 
 

 

출처

 

반응형
블로그 이미지

compcfix

컴퓨터에 문제가 생기면 컴고쳐.kr 에서 해결해 드리겠습니다.

,