Apple II 관련 자료를 뒤적이다 보면 "65C02 필요"라는 단서가 붙은 소프트웨어를 자주 만난다. 같은 6502 계열인데 왜 굳이 칩을 가려 받는지 궁금해서 두 칩의 차이를 한 번 정리해 두기로 했다. 문서를 따라가 보니 단순한 공정 개선이 아니라 명령 세트와 버스 동작까지 손을 댄 개정판이었다.
6502는 1975년 9월 MOS Technology가 25달러에 내놓은 NMOS 8비트 CPU다. 65C02는 그 설계에 참여했던 빌 멘시(Bill Mensch)가 세운 WDC(Western Design Center)가 같은 명령 세트를 CMOS로 다시 만든 후계 칩으로, 1981년 개발을 시작해 1983년 초에 샘플이 나왔다. 기억할 점은 세 가지가 한꺼번에 바뀌었다는 사실이다. NMOS 시절의 알려진 버그가 고쳐지고, 명령과 주소지정 방식이 늘고, 같은 클럭에서 소비전력이 열 배 이상 떨어졌다. 그 대가로 미정의 opcode와 사이클 수에 의존한 기존 코드는 깨졌다.
6502는 성능보다 가격으로 8비트 시대를 열었다
6502 설계는 모토로라 6800 팀 출신인 척 페들(Chuck Peddle)이 주도했고, 빌 멘시가 명령 디코더와 ALU 쪽 설계를 맡았다. 공정은 depletion-load NMOS다. 6800이 +5V 하나를 받아 내부 전압 배가회로로 여러 전압을 만들어 쓰던 것과 달리, 6502는 그런 회로 없이 +5V만으로 동작한다. 참고로 당시 인텔 8080은 아예 세 종류의 전원 전압을 요구했다.
결정적인 요소는 값이었다. 6800은 처음 175달러였고 1975년 10월에 69달러로 내려왔는데, 6502는 25달러로 시작했다. 이 가격 덕분에 Apple I과 Apple II, 코모도어 PET과 VIC-20, 아타리 8비트 기종, BBC 마이크로가 모두 6502 계열을 골랐다.
파생형도 많다. 주소 공간을 8KB로 줄이고 핀 수를 줄인 6507이 아타리 2600에, 6비트 I/O 포트를 붙인 6510이 코모도어 64에 들어갔다. 패미컴과 NES의 리코 2A03은 BCD(십진 연산) 회로를 빼고 음원(APU)과 스프라이트 데이터 전송용 DMA를 얹은 변종이다. 화면을 그리는 일 자체는 별도 칩인 PPU가 맡는다.
65C02는 같은 명령 세트를 CMOS로 다시 그린 칩이다
NMOS는 회로가 정적으로 전류를 흘리는 구조라 대기 상태에서도 전력을 쓴다. CMOS는 상태가 바뀌는 순간에만 주로 전력을 쓴다. 이 차이가 그대로 수치로 나온다. 1MHz 동작에서 원본 6502가 약 450mW를 쓰는 데 비해 65C02는 약 20mW로, 같은 속도 기준 20배 이상 적다.
| 항목 | 6502 (NMOS) | 65C02 (CMOS) |
|---|---|---|
| 발표 | 1975년 9월 | 1981년 개발 시작, 1983년 초 샘플 |
| 개발 | MOS Technology (척 페들, 빌 멘시) | WDC (빌 멘시) |
| 공정 | depletion-load NMOS | CMOS |
| 발표 가격 | 25달러 | - |
| 1MHz 소비전력 | 약 450mW | 약 20mW |
| 미정의 opcode | 동작이 존재 (LAX, SAX 등) | 미사용 자리는 정의된 NOP (변종은 일부를 새 명령으로 활용) |
| 대표 채용 | Apple I/II, PET, VIC-20, 아타리 8비트, BBC 마이크로 | Apple IIc, Enhanced Apple IIe, BBC 마스터(변종 65SC12), 아타리 링스(65SC02 코어) |
라이선스는 GTE, 록웰(Rockwell), NCR, 시너텍(Synertek) 등 여러 회사로 퍼졌다. 16비트로 확장한 후속 65C816은 Apple IIgs와 슈퍼패미컴 CPU 코어로 쓰였다.
65C02가 고친 NMOS 버그 목록
가장 유명한 것은 JMP ($xxFF) 간접 점프다. NMOS 6502는 대상 주소의 상위 바이트를 다음 페이지의 첫 바이트가 아니라 원래 페이지의 $xx00에서 읽어 온다. 65C02는 1사이클을 더 쓰면서 올바른 주소를 읽는다.
십진 모드도 정리됐다. NMOS에서는 BCD 연산 후 N, Z 플래그가 이진 연산 결과를 반영해 사실상 쓸 수 없었다. 65C02는 십진 연산 결과에 맞춰 N, Z 플래그를 세우고, 그 대신 ADC/SBC에 1사이클이 붙는다.
리셋과 인터럽트 진입 시 D(십진) 플래그 처리도 다르다. NMOS는 리셋 후 D 상태가 정의되지 않아 인터럽트 핸들러 앞머리에 CLD를 넣는 것이 관례였다. 65C02는 리셋과 인터럽트에서 D를 자동으로 지운다.
메모리를 대상으로 하는 read-modify-write 명령(ASL, INC, DEC 등)의 버스 동작 차이는 이식할 때 가장 조심할 부분이다. NMOS는 같은 주소에 한 번 읽고 두 번 쓴다. 첫 쓰기가 옛 값이다. 65C02는 두 번 읽고 한 번 쓴다. 쓰기 자체가 상태를 바꾸는 메모리맵 I/O 레지스터를 이런 명령으로 건드리는 코드는 두 칩에서 다르게 동작한다.
인터럽트 관련 버그도 하나 사라졌다. NMOS 6502는 BRK opcode를 페치하는 시점에 하드웨어 인터럽트가 걸리면 BRK가 무시된다. 65C02는 이 경우를 정상 처리한다.
추가된 명령과 주소지정 방식
새 명령은 6502 어셈블리를 쓰다가 아쉬웠던 지점을 그대로 메운다.
BRA: 무조건 상대 분기.JMP보다 1바이트 짧고 위치 독립적이다.PHX,PHY,PLX,PLY: X와 Y를 A로 옮기지 않고 바로 스택에 넣고 뺀다.STZ: 메모리에 0을 저장한다. A를 건드리지 않는다.INC A,DEC A: 누산기 자체를 1 증감한다.TSB,TRB: 비트를 테스트하면서 세거나 지운다.JMP (abs,X): 인덱스가 붙은 절대 간접 점프. 분기 테이블 처리가 짧아진다.- 인덱스 없는 제로 페이지 간접
(zp):LDA (zp)처럼 Y를 0으로 맞추는 준비 동작이 필요 없다.
여기서 주의할 점은 "65C02"가 단일 규격이 아니라는 사실이다. 록웰 R65C02와 WDC 칩에는 비트 단위 조작인 RMB, SMB와 비트 분기 BBR, BBS가 더 있다. 인터럽트까지 대기하는 WAI와 클럭을 멈추는 STP는 WDC 쪽 명령이다. 특정 명령을 쓰는 코드를 다른 회사 65C02에 올리면 동작하지 않을 수 있다.
그래도 코모도어 64는 끝까지 NMOS를 썼다
65C02가 상위 호환이라면 왜 모든 기종이 갈아타지 않았을까. 이유는 NMOS의 미정의 opcode에 있다. 공식 문서에 없지만 실제로 무언가를 하는 opcode가 있었고(LAX, SAX 같은 이름으로 정리된 것들), C64 게임과 데모 씬은 이를 성능 트릭으로 널리 썼다. 65C02는 이 자리를 모두 정의된 NOP으로 채웠으니 그런 소프트웨어는 그대로 오동작한다.
사이클 수 변화도 걸림돌이다. 십진 ADC/SBC와 JMP 간접이 1사이클 늘었고, read-modify-write 계열도 타이밍이 바뀌었다. 래스터 인터럽트처럼 사이클 단위로 화면을 맞추는 코드는 이런 변화 하나에 무너진다. C64가 NMOS 계열 6510을 수명 끝까지 유지한 배경이다.
Apple IIc가 65C02를 고른 이유
Apple IIc는 1984년 4월 24일에 1,295달러로 나왔고 1988년 8월에 단종됐다. 1.023MHz 65C02, 128KB RAM, 오른쪽 측면에 붙은 5.25인치 플로피 드라이브 하나, 무게 3.4kg. 확장 슬롯을 포기하고 Apple II 한 세트를 작은 상자에 넣은 기종이다.
이런 설계에서 CMOS는 선택이 아니라 전제다. 슬롯이 없으니 전원부도 작게 잡을 수 있고, 발열이 줄어드니 팬 없이 밀폐형 케이스를 쓸 수 있다. 추가 명령으로 ROM 코드가 짧아지는 것은 덤이었다. Apple은 Enhanced Apple IIe에도 65C02를 넣어 두 기종의 CPU를 맞췄다.
Apple II 쪽에도 미정의 opcode를 쓰는 코드가 없지는 않아서 Enhanced IIe와 IIc 전환기에 호환 문제가 보고되기는 했다. 다만 C64 데모 씬처럼 그 기법이 문화의 중심은 아니었던 만큼 전환 부담이 상대적으로 작았다.
py65로 두 칩의 차이를 직접 확인한다
가장 손쉬운 방법은 py65다. 파이썬으로 쓰인 6502/65C02 시뮬레이터이며 콘솔 모니터 py65mon을 함께 제공한다. 확인할 것은 고전적인 CPU 판별 기법이다. opcode $1A는 NMOS 6502에서 아무 일도 하지 않는 1바이트 미정의 NOP이지만 65C02에서는 INC A다. Apple II 소프트웨어가 실제로 쓰던 방법이다.
$ pip install py65 $ py65mon -m 6502
-m(또는 --mpu) 옵션이 시뮬레이션할 MPU를 고른다. 지정할 수 있는 값은 6502, 65C02, 65Org16이고 기본값은 6502다. 모니터 안에서 mpu 명령을 인자 없이 실행하면 현재 MPU와 목록을 보여 주고, 인자를 주면 그 자리에서 바꾼다.
메모리에 $1A 한 바이트를 넣고 A에 값을 세운 뒤 한 단계 실행한다.
.fill c000:c000 1a .registers pc=c000, a=41 .step .registers
MPU가 6502면 A는 $41 그대로다. mpu 65C02로 바꾸고 같은 절차를 반복하면 A가 $42로 올라간다. disassemble c000:c000을 비교해 보는 것도 재미있다. 6502를 고른 상태에서는 해석되지 않는 opcode로 표시되고, 65C02에서는 INC A로 나온다.
Apple II 에뮬레이터에서 확인하려면 기종 설정을 바꾸는 쪽이 빠르다. 초기 IIe는 NMOS 6502, Enhanced IIe와 IIc는 65C02이므로 같은 판별 루틴을 두 설정에서 돌려 결과를 비교할 수 있다. 트랜지스터 단위로 6502 내부를 들여다보고 싶으면 visual6502.org의 시뮬레이터를 열어 JMP 간접 버그가 발생하는 순간의 주소 버스를 관찰하는 방법도 있다.
실칩을 구하는 난이도와 참고 자료
65C02는 레트로 부품 중에서 드물게 지금도 신품을 살 수 있다. 현행 W65C02S는 5V에서 14MHz 정격이고, 완전 정적(fully static) 코어라 클럭을 아무 속도로 내리거나 아예 멈춰도 레지스터 상태가 유지된다. Mouser 같은 유통사에서 DIP 패키지를 그대로 판다. Ben Eater의 브레드보드 컴퓨터 시리즈가 이 칩을 쓰는 덕에 배선 예제와 트러블슈팅 자료도 많다.
반대로 원본 NMOS 6502, 특히 초기 화이트 세라믹 패키지나 MOS 로고가 찍힌 칩은 값이 붙는다. 기종에서 뽑아낸 칩은 소켓이 아니라 직접 납땜된 경우가 많아 탈거 과정에서 핀이 상하기 쉽다. 8비트 기종에서 고장 원인으로 자주 지목되는 부품은 CPU보다 전원부 커패시터, RAM, 키보드 접점 쪽이니 CPU부터 의심할 일은 아니다.
더 파려면 NMOS와 CMOS 차이를 항목별로 정리한 Wilson Mines의 NMOS-CMOS 차이 문서와 6502.org의 튜토리얼 및 포럼 아카이브가 출발점이다. MOS의 원본 MCS6500 프로그래밍 매뉴얼과 각 기종 서비스 매뉴얼은 archive.org에서 스캔본으로 볼 수 있다. 명령 세트를 비트 패턴 단위로 이해하려면 6502/65C02/65C816 opcode 해부 문서가 유용하다.