컴퓨터를 만듭시다. 어때요~ 참 쉽죠? (20)

나빌레라의 이미지

#20. 진리를 향하는 여러 가지 방법.

지금까지 길게 이어져온 이야기를 통해 그럴듯하게 보이는 CPU를 만들었다. CPU를 만들기까지 나는 어떤 반도체 소자나 칩을 사용하지 않았다. 그저 전자석과 스위치로 된 릴레이 스위치로부터 트랜지스터의 원리를 유도해 내서 일일이 논리 게이트를 만들고 논리 게이트를 조합해서 메모리와 ALU를 만들었다. 그리고 메모리와 ALU를 조합해서 CPU를 만들었다. 그리고 CPU에 명령을 내리를 방법을 설명하면서 어셈블리어를 만들어냈다. 어셈블리어를 이야기하는 중에 메모리에서 데이터를 가져오는 여러가지 방법을 설명했다. 메모리에서 데이터를 가져오는 방법을 이해할 때 가장 중요한 포인트는 메모리에 주소를 어떻게 지정하느냐 하는 것이다.

메모리에 주소를 지정하는 목적은 당연히 메모리에서 값을 읽거나 메모리에 값을 쓰기 위함이다. 이 읽기, 쓰기 작업을 메모리의 특정 위치에 하기 위해 메모리에 주소를 지정하는 것이다. 하지만 메모리라고 반드시 주소가 있어야 할 필요는 없다. 우리가 만든 CPU에서도 주소가 있는 메모리와 주소가 없는 메모리가 모두 다 있다. 주소가 있는 메모리는 당연히 중심에 있는 64KB의 SRAM이고 주소가 없는 메모리는 여기 저기 흩어져 있는 D 플립플랍으로 만든 레지스터들이다.

그래서 메모리에 값을 쓰는 경우만 생각해 봤을 때 메모리 주소 지정 방식은 두 가지 경우가 도출된다. 용량이 큰 메모리에 메모리의 주소를 지정해서 값을 쓰는 방법과 용량이 버스폭과 일치하는 메모리에 주소를 지정하지 않고 바로 값을 쓰는 방법이다. 메모리에 주소를 지정하는 방법은 다시 몇 가지 방법으로 세분화되고 메모리에 주소를 지정하지 않고 바로 값을 쓰는 방법은 “Immediate Addressing”이라고 부른다. 어떤 책에서는 즉시 주소 지정 방식이라는 뭔가 말도 안되는 용어로 억지로 번역해 사용하기도 한다. 나는 그냥 이메디에이트 어드레싱이라고 쓰거나 Immediate Addressing이라고 영문을 그대로 사용하도록 하겠다.

Immediate Addressing은 어떤 면에서 주소 지정 방식이라고 볼 수 없지만, 많은 자료에서 이 방식도 주소 지정 방식에 포함 시키므로 나도 주소 지정 방식을 이야기하면서 같이 다루겠다. 보통 레지스터에 메모리에서 값을 읽어오는 것이 아니라 값을 직접 줄때 사용하는 방식이다. 이 주소 지정 방식을 가장 많이 사용하는 명령어는 MOV 명령어다.

MOV 레지스터 이름, 상수 값

위와 같이 어셈블리어를 사용할 때 사용하는 주소 지정 방식이다. 우리가 만든 CPU에서는 레지스터 이름에 들어갈 수 있는 레지스터가 A와 B 뿐이다. 만약에 레지스터 B에 0x80을 넣고 싶다면

MOV B, 0x80

이렇게 명령을 주면 된다. MOV 명령 외에도 ADD, SUB, MUL, DIV, MOD 같은 산술 명령어와 AND, OR, XOR 같은 논리 명령어 CMP 같은 비교 명령어의 인자로 광법위하게 쓰인다. 즉, opcode에 주는 인자 중 메모리 접근 용도가 아닌 모든 숫자는 다 Immediate Addressing이라고 보면 된다.

Immediate Addressing은 메모리에서 값을 읽어오지 않기 때문에 처리 속도가 빠르다. 당연하다. opcode를 해석해서 opcode의 인자가 바로 레지스터로 입력되는 것이기 때문에 명령은 한 번에 모두 처리된다. Immediate Addressing은 동작도 단순하고 이해도 쉽다.

이제 본격적으로 주소 지정 방식에 대해 이야기를 풀어볼까한다. 사실 주소 지정 방식은 CPU의 하드웨어 구성이 어떻게 되느냐에 따라서 아주 여러가지가 만들어 질 수 있다. 어떤 상용 CPU의 메모리 주소 지정 방식은 열 몇가지가 있었다고도 한다. 나는 그 것들을 모두 이야기하지 않을 것이다. 왜냐면 내가 만든 CPU에서 열 몇가지의 주소 지정 방식을 모두 지원하지도 않을 뿐더러 앞으로 내가 이야기할 주소 지정 방식만 이해하면 다른 메모리 주소 지정 방식은 다 그것에서 파생되는 것들이기 때문에 쉽게 이해 할 수 있을 것이다.

Immediate Addressing을 제외한 주소 지정 방식은 LDR, STR 같은 메모리에서 값을 읽고 쓰는 명령어와 B 같은 브렌치 명령어에 쓰인다. 브렌치 명령어도 어떻게 보면 메모리에서 데이터를 읽어오는 명령이기 때문이다.

먼저 메모리에 주소를 줄 때 메모리의 Address 핀에 값을 직접 주는 방법이 있다.

위 그림에서처럼 SRAM의 Address 핀의 입력을 PC의 출럭으로 주는 것이 아니라 opcode의 인자 혹은 레지스터 A, B의 출력으로부터 직접 줄 수 있다. 이렇게 메모리 주소를 PC 대신 바로 지정해 주는 방식을 Direct Addressing이라고 부른다. 문자 그대로 직접 주소 지정 방식이라고 번역하기도 한다. Immediate Addressiing을 즉시 주소 지정 방식이라고 번역할 때 보다는 번역 용어가 한결 우리말 스럽다. 하지만 Immediate Addressing을 그대로 영문표기를 사용하기로 했으므로 Direct Addressing도 영문 표기를 사용하기로 하겠다. Direct Addressing도 지정되는 주소의 시작이 어디냐에 따라서 몇 가지로 나뉜다. 내가 만든 CPU에서는 세 가지 정도로 나눌 수 있다.

첫 번째로 Simple Direct Addressing이라는 방법이다. 이름 그대로 가장 단순한 다이렉트 어드레싱이다. opcode의 인자로 지정한 값을 그대로 메모리 주소로 지정하는 것이다.

내가 만든 CPU에서는 버스 폭이 16비트고 opcode에서 명령어가 차지하는 크기가 8비트기 때문에 Simple Direct Addressing으로 지정 가능한 메모리 주소의 크기는 0x00에서 0xFF까지다. 별로 유용하지 않을 것 같지만 만약에 버스 폭이 32비트고 명령어의 크기가 그대로 8비트라면 Simple Direct Addressing으로도 0x000000에서 0xFFFFFF까지 지정이 가능하다. 버스 폭이 클 수록 유용한 주소 지정 방식이라고 볼 수 있다.

간단히 LDR 명령을 통해 알아보면 레지스터 A에 0x34 번지의 값을 읽어오는 명령은

LDR A, 0x34

가 된다. 0x34는 그대로 SRAM의 주소로 입력되고 0x34 번지의 데이터는 레지스터 A에 저장된다.

두 번째로 PC Relative Direct Addressing이라는 방법이다. 역시 Direct Addressing이기 때문에 SRAM의 Address 핀에 입력이 직접 들어오긴 하지만 입력 값은 현재 PC에 opcode의 인자가 더해진 값이다.

중요한 것은 기존 PC의 값은 그대로 유지된다는 것이다. PC는 기준 점으로 의미를 가지는 것이지 PC Relative Direct Addressing으로 인해 PC의 값이 바뀌는 것은 절대 아니다. PC의 값은 매 클럭 펄스 마다 2바이트씩 증가하는 것외에 브렌치 명령을 통해서만 바뀔 수 있다. PC의 값은 그대로 둔 채 Simple Direct Addressing에서는 메모리의 주소로 들어갔던 값이 PC Relative Addressing에서는 PC와 더해진 값이 메모리의 Address 핀에 입력으로 들어간다. 그리고 PC와 더해지는 값은 음수도 가능하다. 그렇기 때문에 PC Relative Addressing에서는 PC를 기준으로 ±0x7F 의 영역을 지정할 수 있다. 마찬가지로 버스폭이 크다면 PC를 중심으로 더 먼 위치까지 주소 지정이 가능하다.

마찬가지로 LDR 명령을 통해서 알아보자. 다만 Simple Direct Addressing과 구분하기 위해 PC Relative Direct Addressing은 opcode의 인자 앞에 #을 붙이도록 하겠다.

LDR A, #0x34

만약 위와 같은 명령이 처리되었을 당시에 PC 값이 0x0046이었다면 레지스터 A에는 (0x0046 + 0x0034) 0x007A 번지의 데이터가 저장된다.

세 번째로 Register Direct Addressing이 있다. 이제는 아마 이름만 보고도 어떤 동작을 하는 주소 지정 방식인지 눈치를 채는 분도 계실것이다. 레지스터의 출력 값이 그대로 메모리의 주소로 입력되는 방식이다. 앞서 이야기한 Simple Direct Addressing과 PC Relative Addressing은 지정 가능한 주소 영역에 한계가 있었지만 Register Direct Addressing은 레지스터의 용량이 16비트므로 전체 메모리 영역에 대해 주소 지정이 가능하다.

64KB 전체 메모리 공간에 대한 주소 지정이 가능하므로 매우 유용하긴 하지만 미리 레지스터에 주소 값을 넣어두어야 한다는 단점이 있다. 명령어를 처리하는 시간 자체는 다른 Direct Addressing 방법들의 처리 시간과 같지만 미리 레지스터에 값을 넣어 놓는 작업이 필요하기 때문에 실질적으로는 명령어 두 개가 필요한 작업이라고 볼 수 있다.

메모리 주소 0x34 번지의 값을 읽어서 레지스터 A에 저장하는 동작을 Register Direct Addressing으로 처리한다면 아래 같은 명령으로 어셈블리어를 작성해야 할 것이다.

MOV B, 0x34
LDR A, B

언뜻 보기에는 별 효용성이 없어 보이지만, 어떤 연산의 결과로 나온 값을 주소로 하는 위치에서 값을 가져오는 동작 등에 많이 쓰인다. 우리가 많이 아는 C언어의 예를 들자면 가장 쉽게 드는 예는 배열의 첨자를 연산을 통해 계산한다음 해당 위치에서 값을 가져오는 동작에 대표적으로 많이 사용한다.

Direct Addressing의 마지막으로 Register-PC Relative Direct Addressing 방법이 있다. Simple Direct Addressing과 PC Relative Direct Addressing의 관계와 마찬가지로 Register의 값에 현재 PC의 값을 더해서 나온 값을 메모리의 주소로 사용한다. 레지스터에 16비트 값을 모두 담을 수 있기 때문에 Register-PC Relative Direct Addressing을 사용하면 현재 PC가 가리키고 있는 메모리 주소를 중심으로 전체 메모리 영역에 접근이 가능하다. 하지만 Register Direct Addressing 만으로도 전체 메모리 영역에 접근이 가능하기 때문에 그다지 효용성은 떨어진다고 본다.

PC Relative Direct Addressing을 구분하기 위해 인자 앞에 #을 붙인 것처럼 Register-PC Relative Direct Addressing 을 어셈블리어에서 표현하기 위해 #을 붙인다.

MOV B, 0x34
LDR A, #B

이런 식으로 어셈블리어 코드가 만들어진다. 마찬가지로 PC 값이 0x0046이었다면 레지스터 A에는 (0x0046 + 0x0034) 0x007A 번지의 데이터가 저장된다.

이렇게 Direct Addressing 방법 중 내가 만든 CPU에서 구현 가능한 방법 네 가지에 대해 이야기했다. 다음으로는 Indirect Addressing 방법에 대해 이야기하겠다. 일단 이름이 Indirect니 주소 지정을 간접적으로 하는 것 같다. 어떤식으로 간접 지정을 하는 것일까. 방법은 간단하다. 일단 Direct Addressing과 동일하게 메모리에 주소를 지정해 준다. 그리고 나온 값을 다시 주소로 지정하는 것이다. C 언어 이야기를 해서 미안하지만 C 언어의 포인터와 같은 개념이라고 이해하면 된다. C 언어에서 포인터가 얼마나 유용하게 사용되는지 안다면 Indirect Addressing 역시 얼마나 유용한지 단번에 짐작할 수 있을 것이다.

Indirect Addressing 방법은 기본적으로 Direct Addressing 방법과 동일한 원리로 동작한다. 주소를 지정해서 나온 결과를 그대로 사용하는 것이 아니라 다시 주소로 사용하는 것만 다를 뿐이다. 그래서 Indirect Addressing 방법에서도 각각 Simple, PC Relative, Register, Register-PC Relative 이렇게 네 가지 방법으로 구분한다.

각각에 대해 다시 설명하는 것은 내용이 반복되므로 하지 않겠다. 기본 동작은 같기 때문이다. 다만 위 그림에서 보면 알 수 있듯이 결과로 나온 값이 다시 SRAM의 Address 핀의 입력으로 들어가고 그 다음에 나오는 SRAM의 출력을 실제 연산에 사용한다는 점이 Indirect Addressing의 가장 큰 특징이라는 점만 확실히 기억하면 된다.

어셈블리어에서 표현할 때도 Indirect Addressing은 Direct Addressing과 부분할 필요가 있다. 각각의 Addressing 방법을 어셈블리어에서 구별하는 규칙은 어셈블러에 따라 모두 다르다. 그러므로 내가 이 이야기에서 소개하는 방법이 절대적인 방법은 아니라는 것을 염두해 두기 바란다. 어디까지나 내가 생각하고 만들어가고 있는 어셈블러에서 이 방법으로 Addressing 방법을 구분한다는 것이다.

Indirect Addressing일 경우 Direct Addressing의 표현 방법에 대괄호[]를 붙여서 구분하도록 하겠다.

Simple Indirect Addressing의 경우 아래와 같이 표현한다.

LDR A, [0x34]

이제부터는 모두 예상이 될것이다. 그래도 계속 쓰련다. PC Relative Indirect Addressing은 아래처럼 표현한다.

LDR A, [#0x34]

Register Indirect Addressing은 아래처럼 표현한다.

LDR A, [B]

이제 좀 민망해지려 한다. 하지만 마지막이니 또 쓰겠다. Register-PC Relative Indirect Addressing은 아래처럼 표현한다.

LDR A, [#B]

Indirect Addressing은 당연히 Direct Addressing에 비해서 느리다. 메모리에 접근해서 값을 읽어온 다음 그 값이 다시 주소로 들어가 비로소 사용할 값을 가지고 오기 때문에 심할 경우 Direct Addressing에 비해 몇 배나 더 느릴 수도 있다. 하지만 Indirect Addressing은 메모리에서 가져온 값을 그대로 주소로 쓰기 때문에 언제나 메모리 전체 영역에 대해 주소 지정이 가능하다.

이렇게 해서 무려 아홉 가지의 주소 지정 방법에 대한 이야기를 마쳤다. 이 이야기 뿐만 아니라 다른 어셈블리어를 공부하더라도 주소 지정 방법에 대한 것은 필히 완벽히 이해를 하고 있어야 제대로 된 어셈블리어 프로그램을 작성할 수 있다. 또한 이전에 어셈블리어를 공부해서 여러 가지 주소 지정 방식에 대해서 이미 알고 있던 분들이라 하더라도 그 주소 지정 방식들이 다 이런식으로 하드웨어적 배선과 밀접한 관계가 있다는 사실을 이 이야기를 읽고 처음 알게된 분들고 계시리라 생각된다. 그리고 이미 알고 있던 분들도 기존의 지식을 다시 한 번 다지는 계기가 되었으면 필자는 이 이야기를 힘겹게 타이핑한 목적을 달성한 것이다.

아래 그림은 그동안 이야기하면서 만들어왔던 CPU의 전체 구조다. 다시 한 번 잘 보면서 음미해 주시기 바란다.

그동안 계속해서 하드웨어를 주제로 가열차게 달려온 이야기가 조금씩 소프트웨어로 무게 중심이 옮겨가고 있다. 하드웨어와 소프트웨어는 분리되어 있는 것이 아니다. 하드웨어를 좀더 편하게 제어하려다 보니 자연스럽게 소프트웨어가 나온 것이고 이 소프트웨어를 더 편하게 제어하려다 보니 계속해서 상위 수준의 소프트웨어가 나오게 된 것이다. 내가 어디까지 이야기할 지는 나도 잘 모르겠으나 확실한 것은 밑바닥 수준의 소프트웨어 이야기는 아마 필요한 만큼 할 것같다. 계속 읽어주시기 바란다.

댓글

chunsj의 이미지

지속적으로 감사드려요. :-)

정주행도 속도를 놓치니 더이상 따라 잡기가... 책으로 나오길 기대하는 중입니다.

나빌레라의 이미지

몇 군데 출판사에 문의해 봤는데 책으로는 출간 안될것 같아요....^^

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

jachin의 이미지

최근엔 응용분야와 밀접한 내용을 다루는 책이 잘 판매된다고 생각해서 원론서나 이론서, 고급 기술서는 출판을 기피하는 경향이 심해요. 하지만 실제 이용하는 응용환경을 구축한다고 하면 받아줄지도 모릅니다.
====
하나는 전부, 전부는 하나

나빌레라의 이미지

그렇게까지 해서 책 내고 싶지 않아요.

응용분야.. 물론 중요하지만,

전 그 기본이 되는 원론, 이론이 더 중요하다고 생각하거든요.

원론, 이론이 없는 응용은 사상누각.

저처럼 안팔릴것, 출판 안될것 뻔히 알면서도 이런거 계속 들이대는 사람도 있어야,

세상이 좀 다양해지지 않을랑가요~^^

P.S 올해 눈 많이 와서 힘드셨겠어요.....

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

----------------------
얇은 사 하이얀 고깔은 고이 접어서 나빌레라

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.