메모리 칩의 폭·뱅크·선택 신호
메모리 칩 여러 개를 같은 주소로 묶어 데이터 폭을 넓히는 방법과 서로 다른 주소 범위를 맡겨 위치 수를 늘리는 방법을 구분하고, 상위 주소 비트로 칩 선택 신호를 만듭니다. CPU의 바이트 주소를 뱅크, 칩 안의 주소, 바이트 레인으로 나누어 코드로 확인합니다.
4K × 8 칩 네 개를 이으면 곧바로 16K × 8 메모리가 될까요? 그렇지는 않습니다. 두 칩을 같은 주소로 함께 고르면 위치의 수는 그대로이고 한 위치에 담기는 비트만 늘어나며, 서로 다른 주소 범위를 맡기면 위치의 수가 늘어납니다. 같은 칩 네 개라도 어떻게 잇느냐에 따라 전혀 다른 메모리가 되는 것입니다. 이 글에서는 메모리 계층과 주기억장치에서 본 칩의 용량 계산을 여러 칩으로 넓히고, 디코더로 어느 칩을 쓸지 고르는 방법을 다룹니다.
같은 주소로 묶어 폭을 넓힌다
이 글의 칩은 4096개 위치에 8비트씩을 담는 4K × 8 칩이고, 칩 안의 주소는 A0부터 A11까지 12비트입니다. 여기서 K는 1024입니다. 두 칩의 주소선 A0부터 A11을 같은 주소에 함께 잇고 두 칩을 동시에 고르면, 한 번의 접근으로 16비트를 읽고 쓸 수 있습니다. 한 칩은 데이터선 D0부터 D7, 곧 낮은 바이트를 맡고, 다른 칩은 D8부터 D15, 곧 높은 바이트를 맡습니다. 이렇게 데이터 비트를 나누어 맡는 묶음을 바이트 레인(byte lane)이라고 합니다. 두 칩이 같은 데이터선에 동시에 값을 내보내는 연결이 아니라는 점에 주의해야 합니다.
이 글에서는 두 칩을 묶어 한 번에 읽는 16비트를 워드라고 부르겠습니다. 이것은 이 예에서 정한 이름일 뿐, 모든 CPU의 워드가 16비트라는 뜻은 아닙니다.
| 구성 | 워드 위치의 수 | 워드의 폭 | 데이터 용량 |
|---|---|---|---|
| 칩 하나 | 4096 | 8비트 | 4 KiB |
| 두 칩을 폭으로 묶음 | 4096 | 16비트 | 8 KiB |
| 그 묶음 두 개를 주소로 나눔 | 8192 | 16비트 | 16 KiB |
상위 주소로 뱅크를 고른다
두 칩을 묶은 것을 뱅크(bank) 하나로 보고, 뱅크 0과 뱅크 1을 둡니다. 여기서 말하는 뱅크는 이 예의 칩 묶음이며, 현대 DRAM 칩 안의 뱅크와 같은 구조라는 뜻은 아닙니다. 워드 주소는 0부터 8191까지이므로 13비트가 필요하고, 아래 12비트 A0부터 A11은 네 칩의 칩 안 주소에 모두 함께 잇고, 맨 위 비트 A12로 어느 뱅크를 쓸지 고릅니다.
칩이 이번 접근에 참여하도록 고르는 신호를 칩 선택(chip select) 또는 칩 활성화(chip enable, CE) 신호라고 합니다. 이 예에서는 1일 때 고른다는 뜻으로 CE0과 CE1을 쓰고, 이 메모리 영역 전체를 쓸지 정하는 신호 E가 1일 때 , 로 만듭니다. E가 0이면 두 신호가 모두 0이고, 어떤 주소에서도 두 뱅크가 동시에 골라지지 않습니다. 1비트를 받아 출력 둘 가운데 하나를 켜는 1:2 디코더와 같은 회로입니다.
| E | A12 | CE0 | CE1 | 고른 칩 |
|---|---|---|---|---|
| 0 | 0 또는 1 | 0 | 0 | 없음 |
| 1 | 0 | 1 | 0 | 뱅크 0의 두 칩 |
| 1 | 1 | 0 | 1 | 뱅크 1의 두 칩 |
컴퓨터구조 · 논리 연결
주소 상위 비트로 두 뱅크를 선택합니다
E=1인 영역에서 A12=0이면 CE0, A12=1이면 CE1을 선택합니다. 각 뱅크의 두 8비트 칩은 16비트 워드를 함께 구성합니다.
활성 높은 CE의 교육 논리입니다. A0~A11은 네 칩의 내부 주소에 공통 연결하며 그림에서 별도 배선은 생략했습니다. 읽기/쓰기·byte enable·전원·전기 타이밍은 본문 조건을 따릅니다.
그림은 뱅크를 고르는 논리만 보여 줍니다. 한 뱅크 안의 두 칩은 같은 칩 안 주소와 같은 CE를 받고, 데이터 레인만 다릅니다. 전원, 접지, 읽기와 쓰기 제어, 출력 지연 같은 실제 배선은 생략했습니다.
바이트 주소를 세 부분으로 나눈다
CPU는 바이트마다 주소를 붙이므로, CPU의 바이트 주소 B를 워드 주소와 레인으로 바꾸어야 합니다. 워드 하나가 2바이트이므로 워드 주소는 B // 2, 레인은 B % 2입니다. 비트로 보면 B0이 레인을, B1부터 B12까지가 칩 안 주소 A0부터 A11을, B13이 뱅크를 고르는 A12를 맡습니다. 그래서 뱅크 0은 바이트 주소 0부터 8191까지, 뱅크 1은 8192부터 16383까지입니다. 워드 주소에서 뱅크가 바뀌는 4095와 4096을 바이트 주소로 착각하면 용량이 절반으로 보입니다.
바이트 주소 8197을 나누어 보겠습니다. 워드 주소는 8197 // 2 = 4098이고 레인은 1입니다. 4098 // 4096 = 1이므로 뱅크 1이고, 4098 % 4096 = 2이므로 그 뱅크의 칩 안 주소는 2입니다. 읽은 16비트 워드의 높은 바이트가 이 바이트입니다. 바이트 하나만 쓸 때는 해당 레인의 칩에만 쓰기를 허용해, 같은 워드의 다른 바이트가 바뀌지 않게 해야 합니다.
def select_bank(enabled, a12):
return int(enabled and not a12), int(enabled and a12)
def locate_byte(byte_address, chip_depth=4096, lanes=2, banks=2):
if not 0 <= byte_address < chip_depth * lanes * banks:
raise ValueError(f"주소 {byte_address}는 메모리 범위 밖입니다")
word_address, lane = divmod(byte_address, lanes)
bank, chip_address = divmod(word_address, chip_depth)
return bank, chip_address, lane
print([select_bank(e, a) for e, a in ((0, 0), (0, 1), (1, 0), (1, 1))])
for address in (0, 8191, 8192, 8197, 16383):
print(address, locate_byte(address))
try:
locate_byte(16384)
except ValueError as error:
print("오류:", error)[(0, 0), (0, 0), (1, 0), (0, 1)]
0 (0, 0, 0)
8191 (0, 4095, 1)
8192 (1, 0, 0)
8197 (1, 2, 1)
16383 (1, 4095, 1)
오류: 주소 16384는 메모리 범위 밖입니다첫 줄은 표의 E와 A12 네 조합에 대한 CE0과 CE1이고, E가 1일 때만 정확히 하나가 켜집니다. locate_byte는 바이트 주소를 레인 수로 나누어 워드 주소와 레인을, 워드 주소를 칩의 위치 수로 나누어 뱅크와 칩 안 주소를 구하며, 결과는 (뱅크, 칩 안 주소, 레인) 순서입니다. 8191과 8192 사이에서 뱅크가 0에서 1로 바뀌고, 8197은 앞에서 손으로 구한 것과 같으며, 16383이 마지막 바이트입니다. 메모리 크기를 넘는 주소는 오류로 거부합니다. 이 코드는 주소를 나누는 계산만 확인할 뿐, 전기 신호나 실제 메모리를 측정한 것은 아닙니다.
실제 부품에서 달라지는 것
실제 칩은 이 교재의 모델과 다른 점이 있습니다. 예를 들어 Infineon CY7C199D 데이터시트의 SRAM은 32K × 8 칩으로 주소선 A0부터 A14를 가지며, 칩 선택(CE)과 출력 허용(OE) 신호가 0일 때 동작하는 활성 낮음(active-low) 방식입니다. 그래서 이 칩을 쓴다면 앞의 CE 신호를 뒤집어 넣어야 하고, 선택되지 않은 칩은 출력을 끊어 데이터선에 영향을 주지 않는 고임피던스(high-impedance) 상태가 됩니다. 읽기와 쓰기에는 OE와 쓰기 허용(WE) 신호의 조건도 맞아야 합니다. 이 설명은 칩의 논리적인 구성만 비교한 것이며, 전압이나 타이밍까지 맞춘 회로 설계 안내는 아닙니다.
DRAM은 핀을 아끼려고 같은 주소선으로 행 주소와 열 주소를 차례로 보내는 주소 다중화를 씁니다. 그래서 주소선 6개로 행 6비트와 열 6비트를 보내는 칩은 개의 위치를 구별하며, 핀의 수만 세어 64개라고 하면 틀립니다. 실제 DRAM의 뱅크, 행과 열의 폭, 명령과 타이밍은 데이터시트에 정해진 대로 따라야 하고, 행과 열을 고르는 원리는 MIT 6.004의 메모리 강의에서 더 볼 수 있습니다.
정리
- 같은 주소로 칩을 함께 고르면 데이터 폭이 넓어지고, 서로 다른 주소 범위를 맡기면 위치의 수가 늘어납니다.
- 폭을 넓힐 때 각 칩은 서로 다른 바이트 레인을 맡으며, 같은 데이터선에 동시에 값을 내보내지 않습니다.
- 칩 안 주소로 쓰고 남은 상위 주소 비트로 칩 선택 신호를 만들어 뱅크를 고르며, 이것은 디코더와 같은 회로입니다.
- CPU의 바이트 주소는 레인, 칩 안 주소, 뱅크 번호로 나뉘며, 워드 주소와 바이트 주소를 헷갈리면 범위를 잘못 계산합니다.
- 실제 칩은 활성 낮음 신호나 고임피던스 출력처럼 모델과 다른 조건이 있으므로 데이터시트를 확인해야 합니다.
연습 문제
1. 더 넓고 더 많게
1K × 8 칩 여덟 개로 2048개 위치에 32비트씩을 담는 메모리를 만듭니다. 한 뱅크의 칩 수, 뱅크 수, 용량을 구하고, CPU의 바이트 주소 4099가 어느 뱅크의 어느 칩 안 주소, 어느 레인인지 구하세요. 레인은 8비트이고 레인 0이 가장 낮은 바이트입니다.
해설 보기
32비트 폭에는 8비트 레인이 4개 필요하므로 한 뱅크는 칩 4개이고, 위치가 2048개이므로 1024개짜리 뱅크가 2개입니다. 용량은 2048 × 32 / 8 = 8192바이트입니다. 바이트 주소를 워드 크기 4로 나누면 4099 // 4 = 1024, 레인은 4099 % 4 = 3이고, 워드 1024는 뱅크 1의 칩 안 주소 0입니다. 칩 여덟 개를 모두 폭을 넓히는 데만 쓰면 64비트 폭이 되지만 위치는 1024개로 늘지 않습니다.
2. 활성 낮음 칩 선택
본문의 메모리를 CE가 0일 때 동작하는 칩으로 만든다면, E = 1, A12 = 0인 접근에서 뱅크 0과 뱅크 1의 CE 핀에는 각각 무엇을 넣어야 하나요?
해설 보기
본문의 논리로는 CE0 = 1, CE1 = 0이므로 뱅크 0을 고르는 접근입니다. 활성 낮음 칩은 0일 때 고른다는 뜻이므로 두 신호를 뒤집어, 뱅크 0의 CE 핀에 0을, 뱅크 1의 CE 핀에 1을 넣습니다. 식으로는 뱅크 0의 핀에 를 넣는 것이라 NAND 게이트 하나로 만들 수 있습니다. 신호의 이름만 보고 극성을 확인하지 않으면 고르지 말아야 할 뱅크를 고르게 됩니다.
3. 더 큰 칩으로 같은 구성
32K × 8 칩으로 본문과 같이 레인 2개, 뱅크 2개인 메모리를 만들면 용량은 얼마이고, CPU의 바이트 주소에서 몇 번 비트가 뱅크를 고르나요?
해설 보기
한 뱅크는 32K × 16비트 = 64 KiB이고 뱅크가 두 개이므로 128 KiB, 곧 바이트입니다. 바이트 주소는 17비트이고, B0이 레인, B1부터 B15까지 15비트가 칩 안 주소 A0부터 A14를, 맨 위 B16이 뱅크를 고릅니다. 실제로 locate_byte(65536, chip_depth=32768)를 실행하면 (1, 0, 0)이 나와, 이 뱅크 1의 첫 바이트임을 확인할 수 있습니다. 칩이 커져도 바이트 주소를 레인, 칩 안 주소, 뱅크로 나누는 방법은 같습니다.
칩을 이을 때는 먼저 데이터 폭을 넓히는 것인지 위치의 수를 늘리는 것인지 정하고, 바이트 주소의 비트마다 어떤 일을 맡는지 표로 적어 보세요. 다음 글 RAID의 용량·패리티·복원에서는 저장장치 여러 개를 묶어 용량과 안전성을 함께 다루는 방법을 살펴봅니다.