본문으로 건너뛰기

© 2026 Molayo

YouTube요약2026. 06. 15. 11:25

256 바이트 RAM 시뮬레이션

요약

Sebastian Lague가 컴퓨터의 기초 원리를 탐구하며 256바이트 RAM을 시뮬레이션하는 과정을 다룹니다. 레지스터를 넘어 주 기억 장치를 구축하기 위해 NOR 게이트 기반의 래치(Latch) 그리드를 설계하는 논리적 과정을 설명합니다.

핵심 포인트

  • 단일 레지스터의 한계를 극복하기 위한 주 기억 장치 설계
  • NOR 게이트를 활용한 메모리 기본 빌딩 블록(Latch) 구현
  • 행과 열 주소 비트를 이용한 메모리 그리드 활성화 원리
  • 컴퓨터 아키텍처의 기초인 메모리 주소 지정 방식 이해

영상: 256 바이트 RAM 시뮬레이션
채널: Sebastian Lague
길이: 25분 49초
출처: 자막 (수동, en-GB)

전사:
안녕하세요 여러분, 컴퓨터가 어떻게 작동하는지에 대한 기초를 탐구해 온 이 시리즈에 다시 오신 것을 환영합니다. 지금까지의 노력은 단일 숫자를 기억할 수 있는 두 개의 4비트 (4-bit) 레지스터 (register)를 포함하는 이 작은 설정으로 정점에 도달했습니다. 예를 들어, 첫 번째 레지스터에는 숫자 15를 저장하고, 두 번째 레지스터에는 10을 저장할 수 있다고 가정해 봅시다. 그런 다음 우리의 ALU (산술 논리 장치)를 사용하여 이 두 값을 가져와 우리가 원하는 어떤 계산이든 수행할 수 있습니다. 덧셈이나 뺄셈이기만 하다면 말이죠.

그래서 15 빼기 10을 하도록 설정하고 클락 (clock) 신호를 주면 — 이제 여기에 결과가 저장된 것을 볼 수 있습니다. 이것은 분명히 믿을 수 없을 정도로 흥미로운 일이지만, 이것을 합리적으로 범용 컴퓨터 (general-purpose computer)라고 부르기 전까지는 아직 갈 길이 남아 있습니다. 그리고 문제적이게도, 우리는 이미 이 작은 시뮬레이션 프로그램에서 공간이 상당히 부족해지고 있습니다. 그래서 저는 오늘 드디어 테스트할 준비가 된 새로운 버전을 점진적으로 만져오고 있었습니다.

보시다시피 꽤 비슷해 보이지만, 몇 가지 중요한 차이점이 있습니다. 예를 들어, 입력 핀 (input pins)은 이제 화면 옆에 묶여 있는 것이 아니라 독립적인 요소로 되어 있어서, 이제 우리가 원하는 대로 확대 및 축소하고 돌아다닐 수 있습니다. 컴퓨터를 구축하기 위한 충분한 공간이죠! 참고로 입력 핀은 이제 4비트 (4-bit) 및 8비트 (8-bit) 변형으로도 제공되어, 그 모든 개별 와이어 (wire)들을 수동으로 관리할 필요가 없습니다. 이는 우리가 더 정교한 것들을 만들려고 시도할 때 우리의 삶을 조금 더 편하게 만들어 줄 것이라고 희망합니다.

좋습니다 — 오늘 제가 도전해보고 싶은 첫 번째 정교한 작업은 우리 컴퓨터의 주 기억 장치 (Main Memory)입니다. 현재 작업 중인 단일 값들을 기억하는 데는 이러한 개별 레지스터 (Register)들이 훌륭하지만, 우리는 다양한 계산의 결과들을 저장하고 필요할 때마다 나중에 다시 접근할 수 있는 훨씬 더 큰 무언가를 원할 것이기 때문입니다. 그럼, 이 레지스터 중 하나를 열어서 내부에 무엇이 들어있는지 다시 한번 확인해 봅시다. 그리 놀랍지 않게도, 단순히 4개의 1비트 (1-bit) 레지스터로 구성되어 있습니다.

물론 이들을 사용하여 주 기억 장치를 구축할 수도 있겠지만, 여기에는 주로 클록 신호 (Clock signal)와의 동기화 (Synchronization)를 처리하기 위한 수많은 로직 (Logic)이 포함되어 있습니다. 메모리의 모든 비트마다 이를 계속해서 복제하고 싶지는 않습니다. 제 생각에 그것은 다소 낭비적이고 느려질 것 같습니다. 어쨌든, 이제 우리는 하나의 데이터 비트를 단단히 고정시키기 위해 각 출력이 다른 쪽의 입력으로 피드백되는 한 쌍의 NOR 게이트 (NOR gate)로 구성된, 일종의 메모리 기본 빌딩 블록 (Building block)에 도달했습니다.

따라서 우리의 계획은 기본적으로 주어진 메모리 주소 (Memory address)에 따라 개별적으로 활성화할 수 있는 이러한 작은 래치 (Latch)들의 거대한 그리드 (Grid)를 만드는 것이어야 한다고 생각합니다. 하지만 우선은 조금 작게, 아마도 4x4 그리드 정도로 시작해 봅시다. 이는 16개의 래치를 모두 커버하기 위해 4비트 (4-bit) 주소가 필요함을 의미합니다. 이 두 개의 주소 비트는 행 (Row)을 지정하고, 나머지 두 비트는 열 (Column)을 지정하는 것으로 생각할 수 있습니다. 예를 들어, 이 왼쪽 하단의 래치는 행과 열 주소 비트가 모두 0일 때만 활성화되어야 한다고 말할 수 있습니다.

그리고 그 옆의 래치 (latch)는 행이 0이고 열이 1일 때만 활성화되어야 하는 식의 과정이 계속됩니다. 이 주소 탐지 (address detection)를 도와줄 새로운 칩을 빠르게 만들어 보겠습니다. 이 칩은 2비트 입력을 가질 것입니다. 이 입력들이 주소의 열 (column) 비트라고 가정해 봅시다. 우리는 이 입력을 단순히 4개의 개별 출력 비트로 디코딩 (decode)하여, 열 0이 활성화되었는지, 혹은 열 1, 열 2, 또는 열 3이 활성화되었는지를 나타내도록 하고 싶습니다. 이건 충분히 쉬울 것 같습니다. 여기에 4개의 AND 게이트 (AND gates)를 배치하고, 각각의 출력에 연결하기만 하면 됩니다.

그다음 0 입력을 탐지하려면, 두 입력 비트가 모두 0인지 테스트해야 합니다. 그러니 두 입력을 빠르게 반전 (invert)시킨 다음, 첫 번째 AND 게이트에 연결해 보겠습니다. 그러면 이제 출력 0이 켜지는 것을 볼 수 있습니다. 이보다 더 쉬운 것은 3 입력을 탐지하는 것인데, 두 입력이 모두 켜져 있는지만 알면 되기 때문에, 단순히 이 AND 게이트에 직접 연결하면 됩니다. 좋습니다, 그럼 2 입력의 탐지를 처리해 봅시다. 이는 첫 번째 비트는 꺼져 있어야 하고, 두 번째 비트는 켜져 있어야 함을 의미합니다.

마지막으로 1 입력을 탐지하려면, 당연히 그 반대입니다. 첫 번째 비트는 켜져 있고, 두 번째 비트는 꺼져 있어야 합니다. 좋습니다, 이 작은 디코더 (Decoder) 칩을 저장하겠습니다. 이름에는 이것이 특히 2비트 입력을 디코딩한다는 것을 명시하겠습니다. 재미 삼아, 방금 우리가 만든 칩의 실제 버전도 보여드리겠습니다. 현재는 0이 선택되어 있고, 그다음은 1, 2, 3입니다. 자, 이제 다시 래치 (latch) 그리드로 돌아가서, 공간을 확보하기 위해 이것들을 빠르게 옆으로 좀 옮긴 다음, 우리가 새로 만든 디코더 (Decoder) 칩 두 개를 가져와서 하나는 열 (columns)에, 하나는 행 (rows)에 연결하겠습니다.

그리고 당연히 이 두 개의 디코더 (Decoder)에 메모리 주소 (memory address) 입력을 공급해야 할 것입니다. 그러면 앞서 이야기했던 것처럼, 여기에 AND 게이트 (AND gate)를 하나 두어 행 0 (row 0)이 활성화되고 열 0 (column 0)이 활성화되면 왼쪽 하단의 래치 (latch)가 작동할 수 있도록 설정할 수 있습니다. 하지만 모든 래치에 AND 게이트를 일일이 추가하는 것은 다소 번거로울 것이므로, 이를 도와줄 작은 칩을 하나 더 만들어 보겠습니다. 그리고 이 칩을 래치와 동일한 데이터 (Data) 및 저장 (Store) 입력과 함께, 새로운 행 (Row) 및 열 (Column) 입력을 갖도록 설정했습니다.

이를 활용하기 위해 래치 하나와 AND 게이트 하나를 추가해 보겠습니다. 사실 두 개가 필요할 것 같군요... 첫 번째 AND 게이트는 행과 열이 모두 활성화되어 있는지, 즉 이 래치가 선택되었는지를 테스트합니다. 그리고 오직 그 조건이 충족되고 저장 (store) 신호가 켜져 있을 때만, 입력 데이터를 래치에 쓰고 싶을 것입니다. 또한 우리는 래치가 선택되었을 때만 래치로부터 데이터를 출력하고 싶습니다. 그렇지 않으면 기본적으로 출력으로부터 분리되어 있어야 합니다.

그리고 이 시뮬레이션에서는 이전에 이야기했던 3상 버퍼 (3-state buffer)를 사용하여 그렇게 할 수 있습니다. 칩 라이브러리에서 빠르게 가져와서 배선해 보겠습니다. 좋습니다, 이제 래치가 선택되지 않았을 때 이곳의 출력 신호가 그냥 검은색으로 표시되는 것을 볼 수 있는데, 이는 하이 (high) 논리 레벨도, 로우 (low) 논리 레벨도 출력하지 않고 완전히 분리되어 있음을 나타냅니다. 오직 행과 열 입력이 모두 켜져 있을 때만 실제로 래치의 상태를 출력하게 됩니다.

현재는 그것이 HIGH 상태가 되지만 — 초기 상태는 그냥 무작위입니다 — 대신 0을 저장하려고 시도해 볼 수 있습니다 — 그러면 이제 출력이 LOW인 것을 확인할 수 있습니다. 좋습니다, 이 작은 1비트 (1-bit) 메모리 셀에 이름을 붙여줍시다, 짧게 MEM-1이라고 부를까요. 참고로 빠르게 언급하자면, 실제 세계의 메모리 셀은 물론 매우 최적화되어 있습니다 — 전체 구조를 가능한 한 작고 신뢰할 수 있게 만들기 위해 단 6개의 트랜지스터 (transistor)와 많은 영리한 아이디어들을 사용합니다.

그 모든 것을 깊이 파고들려면 훨씬 더 발전된 시뮬레이션이 필요하겠지만, 언젠가 그 단계에 도달할 수 있기를 바랍니다. 또한, 이 래치 (latch) 기반 방식은 실제로 상당히 작은 메모리 칩 — 기껏해야 몇 메가바이트 (MB) 정도 — 에만 사용됩니다. 왜냐하면 매우 빠르긴 하지만 물리적 공간을 상당히 많이 차지하기 때문입니다. 그래서 기가바이트 (GB) 영역의 메모리는 일반적으로 대신 커패시터 (capacitor)로 구성됩니다. 물론, 제가 여기 들고 있는 것보다는 다소 작은 것들이겠지만요. 커패시터는 전기 전하 (electrical charge)를 저장하므로, 이것을 연결하면 — 현재는 비어 있으며, 이는 0으로 표현할 수 있습니다 —

하지만 여기에 전력을 공급하면 빠르게 충전될 것이고, 그것을 1이라고 부를 수 있습니다. 그런 다음 그 입력이 사라지면 전하가 남아 있으므로, 단일 비트 (bit)의 정보 — 충전되었는가, 아니면 충전되지 않았는가? — 를 기억하게 됩니다. 하지만 다소 까다로운 점은, 데이터를 읽고 싶을 때 커패시터가 방전 (discharged)되어 메모리가 손실된다는 것입니다. 그리고 전하가 짜증스럽게도 시간이 지남에 따라 그냥 누설 (leak)되어 사라지기도 하는데, 아주 미세한 규모에서 말하자면 이는 1초 미만의 아주 짧은 시간 동안 일어나는 일입니다.

따라서 이러한 종류의 메모리는 내용을 항상 신선하게 유지하기 위해 전체 내용을 지속적으로 읽고 다시 쓰는 데 많은 추가 회로 (extra circuitry)가 필요합니다. 상당히 터무니없게 들릴 수도 있지만, 단 하나의 커패시터 (capacitor)에 메모리 1비트를 저장할 수 있고, 출력을 활성화하거나 비활성화하기 위한 하나의 트랜지스터 (transistor)만 있으면 된다는 사실 덕분에 실제로 매우 조밀하게 만들 수 있습니다. 참고로, 이는 지속적인 리프레시 (refreshing) 때문에 동적 메모리 (Dynamic memory)라고 알려져 있으며, 반면 우리의 래치 (latch) 기반 방식은 정적 메모리 (Static memory)라고 불립니다. 이러한 용어에 대한 짧은 탈선 중에 덧붙이자면, 이 두 방식 모두 지속적인 전원이 필요하며, 그렇지 않으면 당연히 데이터가 손실되기 때문에 휘발성 메모리 (Volatile memory)의 예시이기도 합니다.

전원이 꺼진 상태에서도 무언가를 기억하려면, 데이터를 더 느린 종류의 비휘발성 메모리 (persistent memory)로 전송해야 합니다. 예를 들어, 작은 팔이 뻗어 나와 디스크 위의 미세한 영역의 자기 극성 (magnetic polarity)을 변경함으로써 데이터를 장기적으로 저장할 수 있는 이 오래된 회전식 디스크 (spinning discs) 중 하나가 될 수 있습니다. 어쨌든, 횡설수설은 그만하고 대신 우리의 시뮬레이션이 가진 단순함으로 돌아가겠습니다. 우리는 이미 열 (column) 및 행 (row) 디코더 (decoder)를 설정해 두었지만, 이제 우리가 만든 메모리 셀 (memory cells)의 그리드 (grid)를 만들 것입니다. 그리고 이 모든 것들을 배선 (wire)해 봅시다.

이제 모든 행 (row) 및 열 (column) 비트들을 각 칩 (chip)에 연결해야 합니다. 이 과정에서 최대한 깔끔하게 정리하도록 노력하면서 말이죠. 좋습니다, 행 (rows) 작업이 끝났습니다 — 이제 열 (columns) 차례입니다. 작업이 완료되었으니 간단히 테스트를 해봅시다 — 처음 두 개의 주소 비트 (address bits)에만 집중해 보면, 행 (rows)이 올바르게 선택되는 것 같습니다. 그다음 마지막 두 비트를 토글 (toggle) 해보면... 네, 열 (columns) 또한 올바르게 선택되는 것 같군요. 다음으로, 당연히 데이터 입력 (data input)이 필요합니다 — 그리고 이 또한 모든 셀 (cell)에 배선 (wired up)되어야 합니다.

그다음에는 저장 입력 (store input)이 필요할 것입니다. 하지만 여기서 조금 앞서 생각할 필요가 있습니다. 왜냐하면 이를 확장하기 위해서는, 이 16개 셀로 이루어진 작은 그리드 (grid) 자체가 더 큰 그리드 내의 하나의 셀 (cell)이 되기를 원하기 때문입니다. 따라서 이것은 실제로 자체적인 행 (row) 및 열 (column) 입력이 필요합니다. 그리고 이들을 일관되게 색칠하는 데 주의를 기울입시다. 좋습니다, 이제 AND 게이트 (AND gates) 한 쌍을 가져와서 우리가 만든 첫 번째 셀 (cell)에서와 똑같이 설정할 수 있습니다. 작업이 완료되면 저장 신호 (store signal)를 연결할 수 있습니다.

좋습니다, 모든 입력 (inputs) 처리가 완료되었습니다. 하지만 여전히 모든 셀 (cells)로부터 출력 (outputs)을 모아야 합니다. 우리는 어떤 시점에도 단 하나의 셀 (cell)만이 활발하게 데이터를 출력할 수 있도록 보장함으로써 작업을 쉽게 만들어 두었으므로, 여기로 작은 배선 (wire)을 하나 통과시켜 모든 출력 (outputs)을 직접 하나로 연결하기만 하면 됩니다. 마지막으로, 이 셀 (cell)이 선택되었을 때만 출력이 활성화되도록 다시 한번 설정하고 싶습니다. 자, 이것이 실제로 작동하는지 확인하기 위해 빠른 테스트를 해봅시다. 우선, 현재 주소 (address)에 0을 저장 (storing)해 보고, 그다음 저장 신호 (store signal)를 꺼보겠습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 YouTube Sebastian Lague (절차적 생성)의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0