본문으로 건너뛰기
Background Image
  1. 프로젝트/
  2. Nintendo Entertainment System/

Nintendo Entertainment System - CPU

·10 분·
NES Emulation - 이 글은 시리즈의 일부입니다.
부분 : 이 글

Nintendo Entertainment System
#

NesDev Wiki1와 Nintendo Entertainment System Documentation2 문서를 기반으로 NES 시스템을 정리 하고자 합니다. 해당 문서에서는 하드웨어 및 프로세서에 대한 내용을 많이 담고 있어서 이해를 위해서는 기본적인 마이크로 프로세서에 대한 지식이 요구됩니다.

문제가 발생할 경우 해당 포스트는 삭제 또는 비공개 처리 됩니다.

본문 이미지 출처 - 위키페디아3

CPU 오버뷰
#

메인 CPU는 Richo 2A034 8비트 프로세서로 BCD 모드를 제거한 6502 코어에 22개의 메모리 맵 I/O 레지스터를 가지고 있으며 PSG(Programmable Sound Generator) 사운드, DMA, 게임 컨트롤러 폴링 등의 기능을 추가 한 CPU 입니다.

동작은 NTSC 모드에서 1.79MHz, PAL 모드에서는 1.66 MHz 속도로 동작하며, 리틀엔디안을 사용합니다.

2kB의 온보드 램을 포함하고 있으며, 카트리지를 통해서 최대 8k ~ 1MB 까지 확장된 램을 사용할 수 있으며 대부분 128 ~ 384kB를 사용합니다.

그래픽 처리를 위해서 별도의 PPU(Picture Processing Unit)을 사용하며 2kB의 비디오램, 256B의 OAM(Object Attribute Memory)로 최대 64개 스프라이트 위치, 색상 및 타일 인덱스를 저장하고, 28 바이트의 온-다이 팔레트 램은 배경과 스프라이트 색을 선택할 수 있습니다.

콘솔의 2kB 온보드 램은 타일 맵 및 속성에 사용될 수 있으며, 8kB의 타일 패턴 롬 또는 램이 카트리지에 포함 될 수 있습니다.

시스템은 48개 색상과 6개의 그레이 팔레트를 사용할 수 있으며, 중간 프레임에 새 값을 쓰지 않고 최대 25개 색을 사용할 수 있습니다. (배경색, 3가지 타일 색상 4세트, 3가지 스프라이트 색상 4세트)

NES의 팔레트는 RGB가아닌 NTSC를 기반으로 하며, 화면 중간에 스프라이트를 다시 로드하지 않고 총 64 개의 스프라이트를 화면에 표시 할 수 있다. NES의 표준 디스플레이 해상도는 256 x 240 픽셀로 구성됩니다.

CPU 메모리 맵
#

2A03은 16비트 어드레스 버스를 가지고 있고, $0000-$ffff의 주소로 64kB 메모리를 지원할 수 있습니다.

Zero Page는 $0000-$00FF를 참조 합니다. 이 영역은 메모리의 첫 페이지이자 빠른 실행을 위한 명확한 어드레싱 모드에 의해 사용됩니다. 메모리 영역 중 $0000-$07FF는 $0800-$1FFF에서 세번 미러링 됩니다. 이것은 $0000 에 어떤 데이터를 기록하면 $0800, $1000, $1800 에도 기록이 된다는 의미이며 $2000-$401F에 위치한 I/O 레지스터도 8k 마다 $2008-$3FFF이나 남은 레지스터 영역에 미러링 됩니다. SRAM(WRAM)은 Save RAM이고, 카트리지 내 게임 저장을 위한 RAM에 엑세스 하기 위해 사용 됩니다.

$8000 부터는 카트리지 PRG-ROM에 위치한 어드레스 입니다. PPG-ROM 16KB 뱅크가 오직 하나인 게임은 $8000과 $C000에 모두 로드 되고, 2개의 PPG-ROM 16KB 뱅크를 가진 게임은 하나는 $8000, 나머지는 $C000에 로드 됩니다. 2개 이상의 뱅크를 가진 게임은 어느 뱅크에 로드 할 것인 결정하기 위해서 메모리 매퍼를 이용합니다. 메모리 매퍼는 특정 주소(또는 범위)에 메모리가 기록되는 것을 감시하고 메모리가 기록 될 때 뱅크를 스위칭 합니다.

// CPU 메모리 맵
+--------------------+ $10000       +--------------------+ $10000
|                    |              |                    |
|                    |              |     PPG-ROM        |
|                    |              |     Upper Bank     |
|                    |              |                    |
|      PPG-ROM       |              +--------------------+ $C000
|                    |              |                    |
|                    |              |     PPG-ROM        |
|                    |              |     Lower Bank     |
|                    |              |                    |
+--------------------+ $8000        +--------------------+ $8000
|        SRAM        |              |        SRAM        |
+--------------------+ $6000        +--------------------+ $6000
|   Expansion ROM    |              |   Expansion ROM    |
+--------------------+ $4020        +--------------------+ $4020
|                    |              |   I/O Registers    |
|                    |              +--------------------+ $4000
|                    |              |                    |
|   I/O Registers    |              |       Mirrors      |
|                    |              |     $2000-$2007    |
|                    |              |                    |
|                    |              +--------------------+ $2008   
|                    |              |   I/O Registers    |
+--------------------+ $2000        +--------------------+ $2000   
|                    |              |                    |
|                    |              |       Mirrors      |
|                    |              |     $0000-$07FF    |
|                    |              |                    |
|        RAM         |              +--------------------+ $0800
|                    |              |        RAM         |
|                    |              +--------------------+ $0200
|                    |              |       Stack        |
|                    |              +--------------------+ $0100
|                    |              |      Zero Page     |
+--------------------+ $0000        +--------------------+ $0000
  • 메모리 맵 테이블5
Address rangeSizeDevice
$0000-$07FF$08002KB internal RAM
$0800-$0FFF$0800Mirrors of $0000-$07FF
$1000-$17FF$0800Mirrors of $0000-$07FF
$1800-$1FFF$0800Mirrors of $0000-$07FF
$2000-$2007$0008NES PPU registers
$2008-$3FFF$1FF8Mirrors of $2000-2007 (repeats every 8 bytes)
$4000-$4017$0018NES APU and I/O registers
$4018-$401F$0008APU and I/O functionality that is normally disabled. See CPU Test Mode.
$4020-$FFFF$BFE0Cartridge space: PRG ROM, PRG RAM, and mapper registers (See Note)
  • 카트리지 공간 마지막 부분에 인터럽트 벡터 위치 $FFFA-$FFFB = NMI vector $FFFC-$FFFD = Reset vector $FFFE-$FFFF = IRQ/BRK vector

레지스터
#

6502는 유사한 프로세서보다 적은 수의 레지스터를 가지고 있습니다. 세 가지 특수 목적 레지스터, 즉 프로그램 카운터, 스택 포인터 및 상태 레지스터가 있으며 각각 특정 용도를 가지고 있습니다. 또한 3개의 범용 레지스터, 누산기 및 인덱스 레지스터 X, Y가 있습니다. 데이터를 임시로 저장하거나 정보를 제어하는 데 사용할 수 있습니다.

프로그램 카운터(PC)
#

프로그램 카운터는 다음에 실행할 명령어의 주소를 저장하는 16비트 레지스터입니다. 명령어가 실행되면 프로그램 카운터의 값이 업데이트되며 일반적으로 시퀀스의 다음 명령어로 이동합니다. 값은 분기 및 점프 명령, 프로시저 호출 및 인터럽트의 영향을 받을 수 있습니다.

스택 포인터(SP)
#

스택은 $0100-$01FF 메모리 위치에 있습니다. 스택 포인터는 $0100에서 오프셋 역할을 하는 8비트 레지스터입니다. 스택은 하향식으로 작동하므로 바이트가 스택에 푸시되면 스택 포인터가 감소하고 스택에서 바이트를 가져오면 스택 포인터가 증가합니다. 스택 영역을 초과하는 경우 별도로 오버플로우가 감지되지 않고 스택 포인터가 $00에서 $FF로 순환 됩니다.

누산기(A)
#

누산기는 산술 및 논리 연산의 결과를 저장하는 8비트 레지스터입니다. 누산기는 메모리에서 조회된 값으로 설정할 수도 있습니다.

인덱스 레지스터 X(X)
#

X 레지스터는 일반적으로 특정 주소 지정 모드에 대한 카운터 또는 오프셋으로 사용되는 8비트 레지스터입니다. X 레지스터는 메모리에서 조회된 값으로 설정할 수 있으며 스택 포인터의 값을 가져오거나 설정하는 데 사용할 수 있습니다.

인덱스 레지스터 Y(Y)
#

Y 레지스터는 X 레지스터와 같은 방식으로 카운터로 사용되거나 오프셋을 저장하는 데 사용되는 8비트 레지스터입니다. X 레지스터와 달리 Y 레지스터는 스택 포인터에 영향을 줄 수 없습니다.

상태 레지스터 (P)
#

상태 레지스터는 연산이 실행 될 때마다 세트 또는 클리어 되는 비트 플래그들의 집합으로 구성되는 레지스터 입니다.

  • Carry Flag (C) - 마지막 명령어가 비트 7에서 오버플로우(overflow) 또는 비트 0에서 언더플로우(underflow)가 발생한 경우 캐리 플래그가 세트됩니다. 예를 들어 255 + 1을 수행하면 결과는 0이 되고 캐리 비트는 세트가 됩니다. 이를 통해 시스템은 첫 번째 바이트에서 계산을 수행하고 캐리를 저장한 다음 두 번째 바이트에서 계산을 수행할 때 해당 캐리를 사용하여 8비트보다 긴 숫자에 대한 계산을 수행할 수 있습니다. 캐리 플래그는 SEC(Set Carry Flag) 명령으로 설정하고 CLC(Clear Carry) 명령으로 Clear할 수 있습니다.

  • Zero Flag(Z) - 마지막 명령어의 결과가 0인 경우 제로 플래그가 세트됩니다. 예를 들어 128 - 127은 0 플래그를 세트 되지 않는 반면 128 - 128은 세트합니다.

  • Interrup Disable (I) - 인터럽트 비활성화 플래그는 시스템이 IRQ에 응답하는 것을 방지하는 데 사용할 수 있습니다. 이것은 SEI(Set Interrupt Disable) 명령에 의해 설정되고 IRQ는 CLI(Clear Interrupt Disable) 명령이 실행될 때까지 무시됩니다.

  • Decimal Mode (D) - 10진수 모드 플래그는 6502를 BCD 모드로 전환하는 데 사용됩니다. 이 플래그는 SED(Set Decimal Flag) 명령으로 설정하고 CLD(Clear Decimal Flag)에 의해 클리어 할 수 있습니다. (NES용 6502에서는 사용되지 않습니다)

  • Break Command (B) - BRK(Break) 명령이 실행되어 IRQ가 발생했음을 나타내는 데 사용됩니다.

  • Overflow Flag (V) - 이전 명령어에서 잘못된 2의 보수 결과를 얻은 경우 오버플로우 플래그가 세트 됩니다. 이것은 양수가 예상되었을 때 음수를 얻었거나 그 반대의 경우를 의미합니다. 예를 들어, 두 개의 양수를 더하면 결과 또한 양수가 되어야 합니다. 그러나 64 + 64는 sign bit로 인해 -128 결과 제공합니다. 따라서 이 경우 오버플로우 플래그가 세트됩니다. 오버플로우 플래그는 비트 6과 7 사이와 비트 7과 캐리 플래그 사이에서 캐리의 배타적 논리합을 취하여 결정됩니다. 자세한 사항은 문서의 Appedix A를 참고하시기 바랍니다.

  • Negative Flag (N) - 바이트의 비트 7은 해당 바이트의 부호를 나타내며 0은 양수이고 1은 음수입니다. 이 부호 비트가 1이면 음수 플래그(부호 플래그라고도 함)가 세트됩니다.

// 상태 레지스터
  7   6   5   4   3   2   1   0
+-------------------------------+
| N | V |   | B | D | I | Z | C |
+-------------------------------+
// 5비트는 unused

인터럽트
#

인터럽트는 코드의 순차 실행을 중지하고 인터럽트에 집중하도록 합니다. 인터럽트는 일반적으로 특정 상황에 의해 하드웨어에 의해 발생하지만, 소프트웨어에 의해 트리거될 수 있습니다. NES에는 세 가지 유형의 인터럽트 NMI, IRQ, reset이 있습니다. 인터럽트가 발생할 때 점프할 주소는 $FFFA-$FFFF의 벡터 테이블에 저장됩니다. 인터럽트가 발생하면 시스템은 다음 작업을 수행합니다.

  1. 인터럽트 요청이 발생 인식
  2. 현재 명령의 실행을 완료
  3. 프로그램 카운터와 상태 레지스터를 스택에 푸시합니다.
  4. 더 이상의 인터럽트를 방지하기 위해 인터럽트 비활성화 플래그 설정
  5. 벡터 테이블에서 프로그램 카운터로 인터럽트 처리 루틴의 주소를 로드
  6. 인터럽트 처리 루틴을 실행
  7. RTI(Return From Interrupt) 명령을 실행한 후 스택에서 프로그램 카운터와 상태 레지스터 값을 가져옴
  8. 프로그램 실행 재개

IRQ 또는 maskable 인터럽트는 특정 메모리 매퍼에 의해 생성됩니다. 인터럽트 비활성화 플래그가 설정된 경우 프로세서에서 무시됩니다. IRQ는 BRK(중단) 명령을 사용하여 소프트웨어에서 트리거할 수 있습니다. IRQ가 발생하면 시스템은 $FFFE 및 $FFFF에 있는 주소로 점프합니다.

NMI(Non-Maskable Interrupt)는 각 프레임의 끝에서 V-Blank가 발생할 때 PPU에서 생성하는 인터럽트 유형입니다. NMI는 상태 레지스터의 인터럽트 비활성화 비트의 영향을 받지 않으므로 발생 시 항상 실행이 중단됩니다. 그러나 PPU 제어 레지스터 1($2000)의 비트 7이 지워지면 NMI 트리거를 방지할 수 있습니다. NMI가 발생하면 시스템은 $FFFA 및 $FFFB에 있는 주소로 점프합니다.

Reset 인터럽트는 시스템이 처음 시작될 때와 사용자가 리셋 버튼을 누를 때 트리거됩니다. 재설정이 발생하면 시스템은 $FFFC 및 $FFFD에 있는 주소로 점프합니다. 시스템은 재설정 요청에 가장 높은 우선 순위를 부여하고 NMI와 마지막으로 IRQ가 뒤따릅니다.

NES는 7 사이클의 입터럽트 레이턴시를 가지는데, 이것은 인터럽트 처리를 실행하기 위해서는 7 CPU 사이클이 필요하다는 것을 의미합니다.

// NMI(Non-Maskable Interrupt) 처리

                     Memory
                   +---------+
+---------+ -----> |    P    | $0100 + SP - 2
|    P    |        +---------+
+---------+        |    PC   | $0100 + SP - 1
|    A    |        +---------+
+---------+       /|    PC   | $0100 + SP
|    X    |      / +---------+
+---------+     /  |         |
|    Y    |    /   +---------+
+---------+   /    |         |
|    SP   |  /     +---------+
+---------+ /      |         |
|    PC   |/       +---------+
+---------+        |         |
                   +---------+      --+
              +--> |         | bbaa   |
              |    +---------+        |
              |    |         |        |--- Interrupt Handler
              |    +---------+        |
    Interrupt |    |         |        |
    Handler   |    +---------+      --+
    Address   |    |         |
              |    +---------+
              |    |         |
              |    +---------+
              |  +-|   aa    | $FFFA
              +--| +---------+
                 +-|   bb    | $FFFB
                   +---------+
                   |         |
                   +---------+

어드레싱 모드
#

6502에는 메모리에 액세스하기 위한 몇 가지 다른 주소 지정 모드가 있습니다. 또한 메모리가 아닌 레지스터 컨텐츠 상에서 작동하는 에드레싱 모드도 있습니다. 6502에는 총 13개의 다른 주소 지정 모드가 있으며, 일부 명령어는 둘 이상의 다른 주소 지정 모드를 사용할 수 있습니다. 주소 지정 모드에 대한 자세한 내용은 문서의 Appendix E에서 확인 가능합니다.

명령어 집합
#

6502는 56개의 명령어가 있지만 일부는 다른 주소 지정 모드를 사용하여 여러 변형이 있어 가능한 256개 중 총 151개의 유효한 opcode를 생성합니다. 명령은 주소 지정 모드에 따라 1바이트, 2바이트 또는 3바이트입니다. 첫 번째 바이트는 opcode이고 나머지 바이트는 피연산자입니다.

  • 로드/저장 작업 - 메모리에서 레지스터를 로드하거나 레지스터의 내용을 메모리에 저장합니다.

  • 레지스터 전송 작업 - X 또는 Y 레지스터의 내용을 누산기에 복사하거나 누산기의 내용을 X 또는 Y 레지스터로 복사합니다.

  • 스택 작업 - 스택을 푸시 또는 풀하거나 X 레지스터를 사용하여 스택 포인터를 조작합니다.

  • 논리 연산 - 누산기 및 메모리에 저장된 값에 대한 논리 연산을 수행합니다.

  • 산술 연산 - 레지스터와 메모리에 대한 산술 연산을 수행합니다.

  • 증가/감소 - X 또는 Y 레지스터 또는 메모리에 저장된 값을 증가 또는 감소시킵니다.

  • Shifts - 누산기 또는 메모리 위치의 비트를 왼쪽이나 오른쪽으로 1비트 이동합니다.

  • 점프/호출 - 지정된 주소에서 다시 시작하여 순차적 실행 시퀀스를 중단합니다.

  • 분기 - 조건이 충족되면 지정된 주소에서 다시 시작하여 순차적 실행 시퀀스를 중단합니다. 조건에는 상태 레지스터의 특정 비트 검사가 포함됩니다.

  • 상태 레지스터 작업 - 상태 레지스터에서 플래그를 설정하거나 지웁니다.

  • 시스템 기능 - 거의 사용하지 않는 기능을 수행합니다.

NES Emulation - 이 글은 시리즈의 일부입니다.
부분 : 이 글

관련 글

PS2 듀얼쇼크 컨트롤러 호스트(리더) 구현 및 분석
·15 분
[이미지 출처] 위키페디아 1 2007년 초쯤 마이크로프로세서(이하 MCU) 스터디를 하면서 주로 해외에서 하드웨어 관련 정보를 찾아보던 도중 우연히 어느 일본인이 개인 홈페이지에 플레이스테인션2(이하 PS2) 듀얼쇼크2 컨트롤러(이하 듀속 또는 DS2) 시그널을 분석해서 공유한 페이지를 발견하게 됩니다.