오늘 새벽에 4장 어샘블리어 구현 마무리하고

잠을 너무 늦게자서 피곤하긴한데

 

오늘 안에 5장을 끝낼수 있을지는 모르겠다.

 

 

범용 목적 컴퓨터와 단일 목적 컴퓨터 

일단 이번 장에서는 

1-3장에서 만든 렘, 프로그램 카운터, ALU, 레지스터 등을 가지고

CPU와 컴퓨터를 만드는게 목표이다.

책에서 말하기를 여기서 만드는게 범용 목적 컴퓨터라 하는데,

 

초등학생 때 컴활 준비했을때였던가

정처기 준비할때였던가. 

그때 범용 목적 컴퓨터가 무엇인지에 대해 잘 몰랐는데,

 

뒤에 또 말할거지만

범용 목적 컴퓨터는 우리가 사용하는 PC나 휴대폰처럼 게임이든, 인터넷이든, 음악이든 하나의 목적이 아닌 다양한 용도로 사용할수 있는 컴퓨터를 말하며,

 

 범용 목적 컴퓨터 외 다른 분류로 특수 목적/단일 목적 컴퓨터가 있다.

단일 목적 컴퓨터의 경우 처음 이 단어를 보는 사람에게는 막연할거같은데 나도 그랬었고,

 

 우리 주위를 보면 신호등, 엘리베이터, 밥솥, 냉장고 등 다양한 기계, 전자장치들이 존재한다.

아직 시퀀스에 대해서 잘 아는건 아니지만 이런 기계 중에서는 엘리베이터나 자동 수양장치, 자기 유지 회로 등 프로세서없이 만들어서 사용할 수 있는 시퀀스 시스템도 있고, 

 

 아날로그 시퀀스 만으로는 구현하기는 어려워 프로세서를 이용한 디지털 시스템이 있는데 우리가 사용하는 PC나 휴대폰 외에도 TV나 밥솥, 냉장고도 내부에 프로세서가 들어가 있고 프로그래밍을 하여 사람이 쉽게 사용할수 있고, 원하는 동작을 하도록 되어있다.

 

 이런 냉장고, 식기세척기, 밥솥 등과 같이 아날로그 회로만으로는 구현하기 어려워 사용한 프로세서를 특수 목적/단일 목적 컴퓨터라 하며, 단일 목적 컴퓨터는 PC같은 범용 목적 컴퓨터와는 다르게 밥솥은 밥솥역활만 하도록, 냉장고는 냉장고 역활만 하도록 특정 용도에 한정한 컴퓨터를 의미한다.

 

 범용 목적 컴퓨터와 차이점이라면 다양한 작업을 할 필요가 없으니 계산 성능이나 메모리 공간, 주변 장치등이 범용 목적 컴퓨터에 비해 적이며 저렴하다는 점이다.

 

 정도로 이해하고 있는데, 당장은 이 정도만 이해해도 답답하거나 막히는 일은 없었다.

 

 

외장 프로그램 방식과 내장 프로그램 방식

 컴퓨터 구조를 공부하다 나오면 자주 보는 폰 노이만 구조니 하버드 구조랑 더불어 내장 프로그램 방식이란 단어를 종종 보곤 했었다. 그런데 처음 컴퓨터를 공부 할때는 당연히 프로그램은 컴퓨터 안에 있으니까 원래 내장된거 아닌가? 왜 내장 프로그램이라는 용어가 나온건지 잘 이해가 되지를 않았었다.

 

 전기랑 디지털 논리 회로를 배우면서 동기 카운터를 만들고, 난드투 태트리스에서 ALU, 램 만들면서 이전보다는 좀 더 와닿았는게, 특히 직접 만든 ALU를 시뮬레이터로 테스트를 할때/기계어 어셈블리어 작성한걸 돌리면서 상태 비트 레지스터/C명령어에 따라 +1 연산하기도 -1 연산하기도하고 D+A M+D 든 연산을 하는걸 봤었다.

 

 지난 장에서는 어셈블리어로 곱셈기 프로그램을 짜서 CPU 에뮬레이터로 돌렸었는데, 그 때는 직접 만든 바이너리 코드를 ROM에다가 저장해서 돌린덕에 PC로 지정한 명령어 실행하고, 그다음 명령어 가져와서 ALU에 넣어 실행하고를 반복했었다.

 

 하지만 이런식으로 프로그램을 기억장치에 넣어서 사용하기 전에는 직접 프로세서가 원하는 동작을 하도록, 원하는 값을 넣을 수 있도록 하드웨어를 조작(선을 뺏다 꽂앗다)하여 만들었으며 이를 하드웨어로 프로그래밍 하는 방식을 외장 프로그램 방식이라 하더라.

 잠깐 찾아보니 최초의 전자식 컴퓨터인 애니악이 이런 외장 프로그래밍 방식이라 한다. 디지털 논리회로를 지금 만큼 모르고 애니악이 최초의 컴퓨터니 에드박이니 하는걸 들을때는 그냥 연도 외우는 문젠갑다 싶어 억지로 외웠었는데 애니악과 우리가 현재 쓰는 컴퓨터가 이런 차이가 있다더라. 

 

 당장에 FPGA로 앞서 만든 ALU를 구현한다 하더라도 입력 두개나 상태 입력 비트에다가 +1, -1, +M, 0, not 연산을 하도록 전선을 일일이 연결해서 전원을 줬다면 얼마나 어려웠을까?

 

 

 

하드웨어를 이용한 동작 구현과 소프트웨어를 이용한 동작 구현

 

 그리고 내장 프로그래밍 방식의 장점은 간단한 명령어들을 합쳐서 복잡한 명령어를 구현할 수 있다는 점이다. 가장 최근에 본 예시로 곱셈 연산일거같은데, 위의 ALU 제어 테이블이나 HACK의 어셈블리어 명령어 테이블을 봐도 하드웨어적으로는 곱셈 연산을 만든 적이 없고, 덧셈 뺄샘 그리고 논리 현산 몇개 뿐이다. 

 

@R2
M=0
@R0
D=M
@END
D;JEQ
@R1
D=M
@END
D;JEQ
  (LOOP)
@R1
D=M
@R2
M=M+D
@R0
M=M-1
@R0
D=M
@END
D;JEQ
@LOOP
0;JMP
  (END)
@END
0;JMP

 

 그런데 어떻게 곱셈 연산을 해냈던가? sum = D+M 연산을 D 횟수 만큼 하도록 루프를 돌면서 곱셈한것과 동일한 결과가 나오도록 어셈블리어를 만들었다. 거기다가 명령어 테이블에도 없던 입출력 제어도 ROM에다가 넣어둔 어셈블리어로 할수 있었다. 명령어 테이블에 없는 동작을 어셈블리어, 그러니까 소프트웨어 적으로 구현했는데 하드웨어로 구현할수 없을까?

곱셈기

 잠깐 찾아보면 곱셈이나 나눗셈도 논리 곱셈기, 논리 나눗셈기가 나오는데 직접 하드웨어로 구현할수가 있다. 그런데도 사용하고자 하는 모든 연산을 하드웨어적으로 구현안하는 이유가 ALU로 원하는 모든 연산을 할수 있도록 각 연산들을 하드웨어로 구현해 짚어넣으면 하드웨어로 구현하기 힘든 연산도 있을 것이고, 그 만큼 비용도 비싸지고, 크기도 커진다.

 

 하지만 곱샘 연산 구현때와 같이 ALU에서 제공하는 단순한 연산들로 소프트웨어 적으로 구현하는 것이 하드웨어로 구현하는것 보다 쉽고, 프로세서가 커질 필요도 없으며 소모하는 비용도 늘진 않는다. 지금 당장은 이정도로 이해하고 있고, 이게 RISC와 CISC의 차이인거 같은데 뒤에 또 보자

 

 

컴퓨터 구조 : 튜링 머신과 폰 노이만 구조

아 내장 프로그램 생각 정리하다가

외장 프로그램으로 넘어가고, RISC CISC 얘기까지 가버렸는데,

 

결국에는 이 내장 프로그램 방식이 대표적인 컴퓨터 모델인 튜링 머신이나 폰 노이만 구조같은 컴퓨터 구조의 핵심이 된다.

 

 튜링 머신은 컴퓨터 공부하면서 몇번 들어봤지만 자주 까먹던 개념인데, 실제 물리적인 컴퓨터는 아니고 어떻게 프로그램을 읽고 처리할지 판단하는 추상적인 개념의 컴퓨터라 한다(만든 것도 있긴한데).

 

 잠깐 나무 위키를 봤는데 (위 그림과는 조금 다르지만) 튜링머신은 테이프, 헤드, 상태 기록기, 행동표 등으로 구성되어있다고 한다. 지금 하는거와 빗댄다면 테이프는 기억 장치, 메모리 역활, 헤드는 어드레스 레지스터 역할, 상태 기록기는 상태 레지스터 쯤 되는거 같고, 행동표는 행동을 지시한다니까 프로그램 카운터쯤? 비슷한게 아닌가 싶기도 하다.

 

 결국에는 헤드를 통해 테이프의 값을 읽거나 쓸수 있다는 점에서 튜링 머신도 내장 프로그램 방식이라고 하는거같다.

 

 폰노이만 구조는 지난번에 하버드 구조와 같이 정리했던거 같은데, 내장 프로그램 방식인 만큼 메모리가 내장 되어있으며, 하버드 구조(데이터 메모리와 명령어 메모리가 다른 버스를 이용)와는 다르게 데이터 메모리와 명령어 메모리가 같은 버스를 통해서 CPU에서 읽고 썻었던게 특징이었다.

 

 

메모리

 아무튼 우리가 만든 컴퓨터 HACK은 계속 봤지만 데이터 메모리 RAM과 명령어 메모리 ROM 두개로 나눠져 있으며 어드레스 레지스터 A를 이용하여 데이터 메모리의 값 M == RAM[A] 에 접근하기도 했었다. 근데 아직도 잘 이해안가는 건 어드레스 레지스터 A가 명령어 메모리의 현재 명령을 가리키고 있다고 하는데,

12: @23

13: D=A

위 연산에서 어드레스 레지스터 A는 23이란 값을 저장하고 있지, D=A란 연산의 주소를 가지고 있지는 않았던거같다.

다음에 실행할 거긴 하지만 명령어의 주소를 가지고 있는건 프로그램 카운터가 아니었나?

 

 

어드레스 레지스터 A가 어떻게 명령어 메모리의 명령어 주소를 가리키는가?

아 어셈블리어 천천히 돌리고 나서야 이해가 된다.

 

위 사진을 보면 지금 ROM의 16번지에서 A레지스터에다가 0을 담고

17번 명령어에는 RAM[0]의 값을 데이터 레지스터에 넣도록 하고 있다.

 

그런데 그 다음 줄을 보면 A 명령어와 C명령어로

@22

D; JEQ

가 있는데,

 

이 명령어를 진행하면 @22라는 A 명령어에 의해 A 레지스터에 22가 담기게 되고,

D에 있는 값에 따라 ROM의 22번지로 점프하게 된다.

 

그러니까 여기서 어드레스 레지스터 A는 점프해서 갈 명령어의 주소를 가리키고 있다.

해당 부분의 실제 어셈블리 코드는

@R0
D=M
@END
D;JEQ

인데 어셈블리어에서 작성한 @END가 어셈블리로인해 @22가 된후 기계어로 되어 롬에 올라갔고,

어드레스 레지스터에 담겨져 주소 역활을 한게 되었다.

 

이제야 이해된다!

그래서 어드레스 레지스터 A가

데이터의 주소, 명령어의 주소, 임시 데이터 보관 역활을 하는건가보다.

 

 

CPU

앞에서 메모리니, 어셈블리어니, 명령어니 계속 정리해왔는데, 이제 CPU를 다룰 차례가 되었다. 계속 공부해왔지만 구현했던 ALU, 레지스터, 제어기 등으로 구성되어 있다.

 

ALU : 이름 그대로 산술 논리 연산하는 장치이며, 구현되지 않은 기능은 하드웨어로 구현해도되고 소프트웨어로 구현해도되며 비용이나 성능, 효율성을 고려해서 설계된다.

 

레지스터 : 레지스터는 CPU 안에 있는 작지만 고속의 기억 장치인데 CPU가 아주 빠르게 동작하다보니, 기억 장치 CPU 밖에 있는 메모리라 한다면 메모리에 값을 잠깐 저장한다거나 원하는 값이든 명령어든 가져 오려고 하면 CPU의 작업 속도에 비해 오랜 시간이 걸려 일을 못하고 지연되는데 이를 stavation 기아 상태라고 한다. 이런 기아 상태를 방지하고, 계산 속도를 늘리기 위해 CPU 내부에 작지만 고속으로 읽고 쓰기가 가능한 기억 장치를 둔 걸 레지스터라고 한다. 일반 컴퓨터에서는 레지스터가 많이 존재하지만 우리가 만들 HACK에는 어드레스 레지스터, 데이터 레지스터 그리고 프로그램 카운터 3개 뿐이다.

 

제어 : 어셈블리어를 보면 알수 있지만 명령어들은 ALU에 입력으로 쓰거나, 메모리에서 가져오거나, 레지스터에 잠깐 저장하는 등 각 하드웨어 장치에 읽고/쓰기 등의 동작들 중에서 어떤 동작을 프로그램 실행중에 할지를 의미한다.

 

가져오기 및 실행 : fetch-execute를 가져오기 및 실행이라 적었는데, 대강 의미는 맞으니까 CPU의 과정은 명령어를 가져오고 실행하기의 반복이라 할수 있을거 같다. 에뮬레이터에서 봤지만 CPU는 프로그램이 실행되는 동안 각 사이클(클럭 마다) 명령어 메모리 ROM에서 실행할 명령어(에뮬레이터상에서는 어셈블리어지만 실제로는 이진 기계어)를 가져오게 되고 C 명령어의 c 비트에 따라 어떤 동작을 할지 해석(판단)하여 그 동작을 실행/수행 execute한다. 그래서 이 과정을 fetch-execute 사이클이라고 부르나보다.

 

 

 

 

입출력 장치

 지난 장에서 설명한거지만 컴퓨터 주변장치인 키보드와 화면을 memory mapped i/o 방식으로 ram 상에 화면과 키보드의 메모리맵에 접근해서 값을 읽거나 써왔다. 이런식으로 입출력 장치를 제어하는 이유는 실제 컴퓨터 주변 장치로 키보드, 화면 뿐만 아니라 마우스, 카메라도 있을 것이고, 프린트나 다른 센서 등 수 많은 장치들이 있다. 하지만 이런 장치들 각각을 어떻게 컴퓨터와 연결해서 사용할까 각 장치가 어떤지 다 알아야할까?

 

 그런 번거로움을 줄이기 위해서 각 장치들의 메모리 맵을 RAM의 영역에 배당하여 해당 매모리맵 영역에 접근함으로서 주변장치들을 사용가능하도록 약속한게 memory mapped i/o 방식이고 이덕분에 지난 과제에서 간편하게 스크린과 화면을 제어할수가 있었다.

 

 오늘 새벽에 그 과제를 하면서 너무 피곤하기도 하고 시간이 늦어서 제대로 설명하지는 않았지만, 클럭 사이클마다 각 주변장치의 매모리맵을 보고 (ex. 키보드 입력이 들어오면 화면에 검은칠을 하라)원하는 동작을 하도록 처리하다보니 사람이 보기에는 알아차릴수 없을 만큼 빠르게 반영된다.

 

 그리고 화면은 2차원 배열 형태로 되어있는데, 메모리는 1차원 주소로 접근 했었다. 그런데도 입출력 메모리 맵핑 방식으로 스크린에 접근할수 있었던건 스크린의 2차원 주소를 1차원으로 직렬화를 했기 때문이다. 일일히 적기는 번거로워서 안했지만 1차원으로 변형한 주소를 이용해서 스크린의 모든 픽셀에(정확히는 각 픽셀들을 담은 레지스터에) 접근할수 있었다.

 

 입출력 매모리 맵핑 방식을 사용하기로 약속/표준화 하여 컴퓨터든 주변장치든 서로 상관없이 만들더라도 이런 약속을 지킨 덕분에 주변 장치의 매모리 맵을 할당하고 사용할수 있게 되었다고 이해하면 될거같다.

 

 주변장치 인스톨러 : 그래서인가 예전에 카메라든 프린터든 새로사서 컴퓨터에서 쓰려면 그런 장치를 쓸수 있도록 설치 프로그램을 돌렸는데, 이런 설치 프로그램을 설치하면서 컴퓨터가 새 장치의  메모리 맵과 베이스 주소를 가져서 사용할수 있게 되는거고

 

 디바이스 드라이버 : 리눅스를 공부하면서 보게되는 디바이스 드라이버도 이것도 인스톨러와 해당 입출력 장치의 메모리맵을 설정하고 물리적인 주변장치에서 값을 어떻게 가져올지를 정리하는 프로그램이라고 한다.

 

 

 

 

 

이제 이번장 이론 마지막으로 HACK 컴퓨터의 구성 요소들을 간단하게 보고 과제를 좀 해야겠다.

그래도 이번 장은 생각보다 빨리 정리 끝낼거같네.. 과제가 얼마나 걸릴지는 모르겠지만 ㅋㅋㅋㅋㅋㅋㅋㅋ

 

 

HACK 컴퓨터

 HACK 컴퓨터는 확장자명을 hack으로 하는 기계어 프로그램을 동작시키는 16비트의 폰 노이만 구조의 컴퓨터다. 데이터 메모리인 RAM과 명령여 메모리인 ROM이 컴퓨터에 내장되며 같은 버스, 어드레스 레지스터 A로 접근해서 값 혹은 주소를 읽고 썻었다.

 

CPU

1) 입력

- inM은 이름 그대로 데이터 메모리에서 가져오는 값

- instruction인 A 명령어 혹인 C명령어로 A 명령어일때는 A=값,  C명령어일땐 명령을 수행 or A/D/M 레지스터 중 지정된 곳에 저장(C 명령어의 목적지가 M이면 writeM은 쓰기 명령을 위해 1이되고, 그렇지 않으면 0이된다. 결과는 outM)

- reset이 0이면 다음 명령을 하지만 1이되면 프로그램 카운터가 0을 가리킨다.

* 주의사항 : 출력 outM과 writeM은 조합 논리회로로 구현되서 명령어 실행 즉시 반영된다!

                출력 addressM과 pc은 순차 논리회로로 구현되어 다음 타임 스탭, 클럭에서 반영된다.

 

 

명령어 메모리

 ROM32K이기도 하며, 0000 0000 0000 0000 ~ 0111 1111 1111 1111 2^15(32K)만큼 접근할수 있고, 한 레지스터가 16비트로 이뤄지다보니 출력은 16비트 크기를 갖는다. ROM이다 보니 어드레스로 접근은 해도 쓰기 작업은 없어 in이나 load 단자는 없다.

 

입출력 장치

 화면과 키보드는 데이터 메모리 RAM에 매핑되어 사용되고, 클럭마다 반영되는데 이 장치들의 매모리 맵을 별도의 빌트인 칩인 Screen과 Keyboard으로 다룬다고 한다. 이것들이 따로 있다는건지 아니면, 램 상에 들어있는걸 칩이라고 부르는지는 잘 이해는 안되지만 일단은 좀 더보자

 

 화면 메모리 맵 : 쓰기 작업을 하다보니 전에 구현한 RAM과 비슷하게 address와 load 입력을 받는다. 차이라면 스크린 공간이 8K다보니 주소가 13비트 입력으로 되어있다.

 

 키보드 메모리 맵 : 키보드 베이스 어드레스의 위치에 있는 레지스터 하나의 값으로 키보드 입력을 나타내다보니, 입력 값이나 주소가 필요없고, 16비트 출력만 내보낸다.

 

데이터 메모리 RAM

 앞서서 스크린과 키보드를 칩으로 나타내고 있으니까 순간 혼동했는데 RAM4K, RAM16K를 구현할 떄 처럼 저만 스크린, 키보드 칩은 그냥 저 크기를 가지는 주변장치의 입출력을 저장하는 기억장치였다. 이 주변장치들이 RAM 안에 포함되어 있어서 16K와 합친다고 별도의 칩으로 표현해놓은 것이고, 결국에는 RAM = RAM16K + 스크린(RAM8K) + 키보드(레지스터, 읽기전용) 하여 데이터 메모리를 구현하나보다.

 

 

 

컴퓨터

드디여 난드 투 테트리스의 마지막 하드웨어인 컴퓨터를 구현할 차례다. 프로그램을 어떻게 집어 넣는지는 아직 잘은 모르겠지만 앞서 만든 CPU와 RAM, ROM을 잘 조합한게 컴퓨터이고, 이 컴퓨터는 reset 입력만 받는다. 0일때는 그대로 프로그램 카운터 진행되는데로 연산하지만 reset 1이 되었다가 0이되면 프로그램 카운터가 0이되어 다시 시작한다. 

 

 

와 벌써 하드웨어 마지막 과제라니 내가 이걸 주말부터만들기 시작해서 이제서야 5장까지 왔다.

책 페이지로는 1/3 조금 넘게 밖에 못온게 너무 충격이긴한데,

디지털 논리회로만 넘기면 나머지는 쉬울줄 알앗지만 장난아니었다.

 

2년전에 ALU하다가 포기하기도 했었고

이번에 다시하면서 처음에 논리회로 만들때만 해도 포기하고 싶었는데 계속 하다보니까 컴퓨터 구현까지

생각보다 많이 왔다.

 

근데 이속도로 어셈블러, 가상머신, 컴파일러, 고급언어, 운영체제까지 하려면 다음주까지는 걸릴것같네 ...

되게 유익하기는 한데 시간 엄청 잡아먹고 있긴하다.

 

아무튼 이론 글은 여기까지 하고

과제 하는거보고 다음 글을 써야겠다.

 

+ Recent posts