그래픽은 PPU(Picture Processing Unit) 라고 불리는 전용 칩에 의해 생성됩니다. 이것은 NES에 정체성을 부여하는 칩 중 하나입니다. 다시 말해, 누구나 하드웨어 스토어에서 6502 CPU를 구할 수 있으므로, NES가 예를 들어 Apple 2나 Commodore 64와 어떻게 다른가요? NES를 다른 기기와 구별해주는 것은 CPU 주변의 칩입니다: PPU와 APU입니다. 이들은 각각 NES의 고유한 그래픽 및 오디오 기능을 구성합니다.
즉, PPU는 스프라이트와 백그라운드라고 불리는 2D 그래픽을 렌더링하여 비디오 신호에 출력을 발생시킵니다.
콘텐츠 정리
무언가를 화면에 렌더링하려면, PPU는 어떤 그래픽을 그릴지, 어디에 배치할지, 어떻게 그릴지 (즉, 어떤 팔레트를 사용할지)를 알아야 합니다.
이 질문에 답하기 위해, PPU는 특정 유형의 데이터를 찾는 다른 메모리 맵으로 사전 프로그래밍되어 있습니다.
- 그래픽 데이터는 게임 카트리지에서 가져오며, 이 카트리지는 문자 메모리라는 전용 칩을 포함하고 있으며, 이 칩은 패턴 테이블이라는 데이터 구조에 조직된 2D 도면 (타일이라고 함)을 저장합니다. 문자 메모리는 게임이 불변의 그래픽 세트를 포함하는지 또는 CPU가 개입해야 하는지에 따라 '읽기 전용 메모리' (ROM) 또는 '램덤 액세스 메모리' (RAM) 형태로 구체화됩니다.
- PPU는 최대 8 KB의 캐릭터 메모리를 두 개의 4 KB 그룹으로 구성하여 주소 지정합니다.
- PPU에게 그래픽을 '어디에', '어떻게' 그릴지를 알려주는 메타 데이터는 다른 영역에 있습니다:
- 별도의 2 KB의 SRAM이 마더보드에 장착되어 있으며, 이번에는 그래픽 관련 데이터에 전용됩니다. 닌텐도는 이 공간을 비디오 RAM (VRAM)이라고 부르며, 두 개의 네임테이블이라는 데이터 구조를 저장합니다.
- PPU는 256 B의 DRAM을 포함하여 객체 속성 메모리(OAM)를 저장합니다.
- 마지막으로, PPU는 색상 팔레트를 정의하기 위해 4B의 메모리를 포함하고 있습니다.
새로운 용어에 대해 걱정하지 마세요, 이 데이터 구조의 의미는 다음 단락에서 단계별로 설명됩니다.
프레임 구성
동시대 제쳄들과 마찬가지로, 이 칩은 CRT 디스플레이의 동작에 맞게 설계되었습니다. 프레임 버퍼는 없습니다. PPU가 CRT빔과 보조를 맞춰 렌더링 되어 이미지를 즉시 생성합니다.
PPU는 256x240 픽셀의 고정 치수로 프레임을 그립니다 . 안타깝게도 세계 각국의 아날로그 비디오 표준의 차이로 인해, NTSC나 PAL 등 디스플레이 장치의 지역에 따라 이미지의 외관이 달라집니다. 간단히 말해, NTSC 텔레비전은 오버스캔을 수용하기 위해 상단과 하단 가장자리를 잘라낼 것이므로 (약 224개의 스캔라인만 보임), 개발자가 게임의 요소를 배치할 위치를 결정할 때 이 가장자리는 '위험 지역'으로 간주됩니다. 반면, PAL 텔레비전은 가장자리를 자르지 않지만 더 높은 신호를 채우기 위해 추가 검정 막대를 표시할 것입니다 (PAL은 288개의 스캔라인을 사용).
한편, PPU가 출력하는 프레임은 두 개의 서로 다른 레이어로 구성됩니다. 시연 목적으로 Super Mario Bros.를 사용하여 이 기능의 작동 방식을 보여드리겠습니다.
타일

단일 타일입니다.
우선, PPU는 스프라이트와 백그라운드를 생성하기 위한 기본 재료로 타일을 사용합니다.
NES는 타일을 기본 8x8 픽셀 맵으로 정의하며, 이는 Character 메모리 (게임 카트리지에 위치) 내에 저장되고 패턴 테이블이라는 큰 데이터 구조로 조직됩니다 . 각 타일은 16 B를 차지하며 패턴 테이블은 256개의 타일을 포함합니다 . PPU가 최대 8 KB의 Character 메모리에 접근하므로, 최대 두 개의 패턴 테이블에 접근할 수 있습니다.
타일 내부에서 각 픽셀은 팔레트의 네 가지 색 중 하나를 참조하는 2비트 값으로 인코딩됩니다. 프로그래머들은 최대 8개의 팔레트(배경용 4개, 스프라이트용 4개)를 정의할 수 있습니다. 각 팔레트에서 참조하는 색상은 총 64가지 색으로 구성된 '마스터 팔레트'를 가리킵니다. 이 팔레트는 이 콘솔이 생산할 수 있는 모든 색을 나타냅니다. 팔레트는 네 가지 색으로 구성되며, 그 중 하나는 투명으로 예약되어 있습니다.
화면에 그림을 그리기 시작하기 위해, 게임은 캐릭터 메모리에 있는 타일을 참조하는 테이블 세트를 채웁니다. 각 테이블은 프레임의 한 레이어(스프라이트 또는 배경)에 책임이 있습니다. 그런 다음, PPU는 해당 테이블에서 데이터를 읽어 CRT 건에 의해 전달될 스캔 라인을 구성합니다.
이제 각 레이어/테이블이 어떻게 작동하고 기능적으로 어떻게 다른지를 설명하겠습니다.
배경 레이어
좌우로 스크롤이 가능한 수직 미러링을 사용하여 설정된 백그라운드 맵으로 그러나, 단 한쪽만 사용할 수 있습니다.백그라운드 레이어는 정적 타일을 포함한 512x480 크기의 맵 입니다. 보이는 프레임이 훨씬 작기 때문에, 게임은 표시될 레이어의 부분을 선택합니다. 게임은 플레이 중에 레이어에서 '화면에 보여주는 영역'을 이동할 수도 있습니다. 이것이 스크롤 이펙트가 작동하는 방식입니다.
메모리를 절약하기 위해, 4개 타일 그룹이 16x16 픽셀 맵으로 결합되며, 이 맵 내의 모든 타일은 같은 색상 팔레트를 사용해야 합니다.
네임테이블(Nametables) (VRAM에 저장됨)은 백그라운드 레이어에서 표시할 타일을 지정합니다. PPU는 레이어의 사분면에 해당되는 1024바이트의 네임테이블 네 개를 찾습니다. 그러나 VRAM에서 사용 가능한 공간은 2KB에 불과하기 때문에 따라서 추가 하드웨어 없이 두 개의 네임테이블만 저장할 수 있습니다. 그래도 남은 두 개는 어딘가에서 다루어져야 합니다. 대부분의 게임들은 남은 두 개가 처음 두 개가 있는 곳을 가리키도록 합니다 (이것을 미러링이라고 합니다).
이 아키텍처는 결함이 있는 것처럼 보이지만, 실제로는 단순한 확장성을 제공하면서 비용을 절감하도록 설계된 것입니다. 게임이 더 넓은 백그라운드가 필요하다면 추가적인 VRAM을 카트리지에 포함할 수도 있게 만들었습니다.
각 네임테이블의 마지막 바이트는 각 블록에 할당된 색상 팔레트를 지정하는 64바이트 속성 테이블을 저장합니다.
스프라이트 레이어
스프라이트는 화면에서 움직일 수 있는 타일입니다. 또한 서로 곂치거나 백그라운드 뒤에 있을 수도 있습니다. 표시될 그래픽은 우선순위 값에 기반하여 결정됩니다 (전통적인 그래픽 디자인 소프트웨어의 '레이어' 개념과 동일).
Object Attribute Memory (OAM) 테이블은 스프라이트로 사용될 타일을 지정합니다. 타일 색인(index) 외에도 각 항목에는 (x,y) 위치와 여러 속성들(색상 팔레트, 우선순위 및 플립 플래그)이 있습니다. 이 테이블은 PPU 칩에 있는 256바이트 DRAM에 저장됩니다.
OAM 테이블은 CPU를 활용해서 채울 수 있지만, 이렇게 하면 실제로 매우 느릴 수 있고 (적절한 시기에 수행되지 않으면 프레임이 손상될 위험이 있음) 그래서 PPU는 (PPU 레지스터를 변경함으로써) WRAM에서 테이블을 가져오도록 프로그래밍된 DMA(Direct Memory Access)라는 작은 구성 요소를 포함하고 있습니다. DMA를 사용하면 다음 프레임이 그려질 때 테이블이 업로드 되는 것은 보장됩니다. 하지만, 전송 중에는 CPU가 중지됩니다!
PPU에서 스프라이트는 스캔라인당 8개, 프레임당 64개로 제한됩니다. 스캔라인 제한은 'OAM 순서 회전'이라는 기법 덕분에 초과될 수 있습니다. 이 기법에서는 게임이 수동으로 OAM의 항목 순서를 변경합니다. 이로 인해 PPU는 각 프레임에서 다른 스프라이트 세트를 렌더링하여, CRT 빔의 속도가 사용자를 허용된 스프라이트 수보다 더 많이 보이게 만듭니다. 그러나 스프라이트는 화면에서 깜박거리는 것처럼 보일 수도 있습니다.
배경 분할

다른 스크롤링 값이 정의된 두 부분을 강조 표시한 렌더링된 배경 레이어. 마리오가 움직일 때 두 번째 부분만 스크롤됩니다.
넘어가기 전에, 아직 말하지 않은 것이 있습니다. Super Mario Bros를 플레이해보면, 마리오가 움직일 때 장면이 원활하게 스크롤되는 것을 알 수 있습니다. 그러나 통계를 표시하는 상단 영역은 고정된 상태로 유지됩니다! 같은 백그라운드 레이어의 일부인데도 불구하고! 그렇다면 여기에 어떤 일이 일어나고 있을까요? 이 작업을 수행하기 위해, 게임은 스크롤 값을 중간 프레임에서 변경하여 오버월드와 통계(백그라운드의 고정된 부분에 위치)를 동시에 표시합니다. NES는 이 기능을 기본적으로 제공하지 않지만, 게임은 PPU 상태 레지스터()를 통해 PPU의 상태를 관찰하여 타이밍을 추론합니다.
이를 달성하기 위해, 게임은 Sprite 0 Hit이라고 하는 기술을 사용합니다. Super Mario Bros는 프레임 내에서 처음으로 그려지는 스프라이트 뒤에 더미 스프라이트를 렌더링하도록 PPU에 지시합니다. PPU가 이를 빔으로 발사한 후, 첫 번째 스프라이트('스프라이트 0')가 그려졌음을 나타내는 플래그를 상태 레지스터에 업데이트합니다. 한편으로, 게임은 끊임없이 프레임 중간에 스프라이트 0 상태가 플래그가 되었는지(일명 '히트')를 확인합니다. 만약 그럴 경우, 게임은 배경 테이블의 스크롤링 속성을 업데이트하여 마리오가 있는 곳으로 이동시킵니다.
전체적으로 'Sprite 0 Hit'는 매우 섬세한 절차입니다. 타이밍이 너무 쉽게 엉망이 될 수 있기 때문입니다 (sprite 0의 플래그는 검사 후 지워지지 않으므로 '중복된' 긍정으로 이어집니다) . 또한 이 루틴이 무한히 반복되므로 실행하는 데 상당한 비용(CPU 주기 측면에서)이 들 수 있습니다. 다행히도, 나중에 나온 매퍼는 임의의 스캔라인에 도달할 때마다 자동 인터럽트를 사용하여 이 기능을 대체했으며 (훨씬 효율적인 기술), 예를 들어 Super Mario Bros 3의 시각적 기능이 크게 향상되었습니다.
결과
프레임이 완성되면 다음 프레임으로 넘어갈 때입니다!
그러나, CPU는 PPU가 현재 사용 중인 테이블을 수정할 수 없습니다. 그렇지 않으면 화면에 아티팩트가 나타날 수 있습니다. 따라서 모든 스캔 라인이 완료되면, PPU는 CPU에서 Vertical Blank (V-Blank) 인터럽트를 트리거합니다. 이것은 게임에 현재 표시된 그림을 지우지 않고 테이블을 업데이트할 수 있음을 알립니다. 이때 CRT 빔이 '화면에 보여주는 영역' 아래(오버스캔 영역)를 가리킵니다. (또는 하단 테두리 영역)
V-Blank 윈도우 외부에서 갱신할 수 있는 PPU 레지스터는 소수에 불과합니다. 이것이 배경 레이어를 중프레임에서 스크롤할 수 있는 이유를 설명합니다.
비밀과 한계점
전체 프레임을 저장할 수 있는 충분한 메모리를 갖춘 프레임-버퍼 시스템이 바람직하지만 RAM이 비용이 비싸고 콘솔의 목표는 저렴해지는 것입니다. 이제 이 디자인이 매우 효율적이고 유연하기까지 한데도 말입니다.
멀티 스크롤링

슈퍼 마리오 브라더스 2. 수직 스크롤링을 위한 네임테이블 설정 (수평 미러링).

슈퍼 마리오 브라더스 3. 마리오가 달리고 날 수 있기 때문에 PPU는 대각선으로 스크롤을 해야합니다. 오른쪽 가장 자리가 잘못된 색상 팔레트를 보여주고 있습니다! 왼쪽 가장 자리는 마스크가 적용되어 있습니다.
몇몇 게임들은 주인공이 수직으로 움직여야 하는 경우가 있어, 수평 미러링으로 네임테이블을 설정합니다. 다른 게임들은 캐릭터가 좌우로 움직여야 하므로 대신 수직 미러링을 사용합니다.
어떤 유형의 미러링이든 사용하여 PPU가 사용자가 눈치채지 않는 사이에 배경 타일을 갱신할 수 있습니다: 새로운 타일이 렌더링되는 동안 스크롤할 공간이 충분합니다.
하지만 캐릭터가 대각선으로 움직이려면 어떻게 될까요? PPU는 어떤 방향으로든 스크롤할 수 있지만, 추가 VRAM이 없으면 가장자리는 동일한 색상 팔레트를 공유해야 합니다(타일이 블록으로 그룹화됨을 기억하세요).
이것이 슈퍼 마리오 브라더스 3와 같은 일부 게임에서 마리오가 움직일 때 화면 오른쪽 가장자리에 이상한 그래픽이 나타나는 이유입니다(게임은 수직 스크롤링으로 설정됨) . 이들은 하드웨어 비용을 최소화해야 했을 가능성이 있습니다 (이 게임에는 이미 강력한 맵퍼가 설치되어 있음).
흥미로운 해결책: PPU는 타일 위에 수직 마스크를 적용할 수 있게 하여 글리치 영역의 일부를 효과적으로 숨길 수 있었습니다.
타일 스와핑
특정 스캔 라인 동안 사용할 수 있는 타일을 사용하여 렌더링된 가상 프레임.슈퍼 마리오 브라더스 3의 또 다른 특별한 점은 표시할 수 있는 그래픽의 양입니다.
이 게임은 허용된 것보다 더 많은 배경 타일을 표시합니다. 그래서 어떻게 그런 걸까요? 디스플레이가 생성되는 동안 다른 시간에 두 개의 화면 캡처를 보면 최종 프레임이 실제로 두 개의 다른 프레임으로 구성된 것을 볼 수 있습니다.
이것은 MMC3 매퍼의 매직 중 하나로, 추가 공간을 액세스할 수 있도록 프로그램 ROM에 사용될 뿐만 아니라 두 개의 다른 캐릭터 칩을 연결하여 캐릭터 ROM 공간을 확장합니다. PPU가 요청하는 화면 부분을 확인함으로써, 매퍼는 어느 칩으로든 리디렉션하여 원래 지원하는 것보다 더 많은 고유한 타일을 화면에 표시할 수 있게 합니다 .
호기심을 자극하는 행동
연구를 진행하면서, PPU의 특이한 동작을 설명하는 많은 흥미로운 기사를 접했습니다. 그래서 몇 가지를 여기에서 언급하려고 합니다:
- RGB 색상을 생성하여 방송을 위해 NTSC/PAL 신호로 인코딩하는 마스터 시스템 VDP와 달리, NES의 PPU는 모든 작업을 한 번에 처리합니다 . 따라서 PPU 마스터 팔레트의 색상과 현재 기술에서 널리 채택된 표준 RGB 색공간 사이에는 일대일 연결이 없습니다. 이로 인해 해석의 여지가 생기고, 결과적으로 다양한 에뮬레이터가 다른 팔레트를 표시할 수 있습니다.
- RGB 팔레트 간의 차이는 Tim Worthington의 DIY 키트를 통해 가장 잘 드러납니다. 왜냐하면 이 키트는 NES에 RGB 신호 출력을 추가하고 세 가지 미리 정의된 팔레트 중 하나를 선택할 수 있는 스위치를 구현하기 때문입니다 .
- 마스터 팔레트에는 NTSC TV 신호를 망칠 수 있는 '저주받은' 색상 (
$0D)이 포함되어 있습니다 . 일부 TV는 해당 색상을 표시하는 신호를 블랭킹 신호로 혼동하기 때문에 깜박임이 발생할 수 있습니다. - PPU는 객체 속성 메모리(OAM)를 저장하기 위해 DRAM에 의존합니다. 이제, DRAM은 데이터를 잃지 않기 위해 지속적으로 리프레시가 필요합니다 (SRAM과 달리), 그리고 PPU는 프레임을 렌더링하지 않을 때 DRAM을 리프레시하지 않습니다 . 이는 수직 블랭킹 동안 나타납니다. 이러한 이유로, V-블랭킹이 발생하는 동안의 비-리프레시 기간 동안 테이블의 일부가 손상될 것이기 때문에 V-블랭킹 외부에서 OAM을 업데이트하지 않는 것이 좋습니다.
- PAL 시스템용 PPU 변형은 V-블랭킹 동안 리프레시가 수행되므로 이에 영향을 받지 않습니다 (PAL 시스템에서 V-블랭킹이 더 오래 지속됨).







