원문 캡처 · github.com
원문 캡처 · github.com

c64-hw-sim은 Commodore 64의 ASSY 250407 메인보드를 핀 단위로 시뮬레이션한다. 칩 핀을 들어 올리거나 접지·+5V에 연결하고, 칩을 소켓에서 빼거나 저항을 끊은 뒤 모니터 화면과 키보드, 보드의 신호가 어떻게 달라지는지 볼 수 있다.

시뮬레이터는 회로 기판의 전기 연결 정보와 각 칩 핀의 동작을 바탕으로 결과를 계산한다. 고장 난 C64의 모습을 미리 정해 두고 재현하는 방식은 아니다. 예를 들어 전원을 켜기 전에 컬러 RAM의 17번 핀(A7)을 들어 올리면 기기가 정상처럼 부팅된다. CPU가 쓰고 VIC가 읽을 때 같은 잘못된 주소를 사용해 RAM 주소가 겹치기 때문이다. 핀을 다시 연결하면 기록되지 않았던 컬러 RAM 영역이 무작위 색으로 나타나며, 핀을 다시 들어 올리면 화면이 깨끗해진다. 원문은 실제 2114 칩도 같은 현상을 보인다고 설명한다.

이 프로그램은 Commodore 64의 작동을 실제 하드웨어를 손상할 위험 없이 자세히 살펴보거나, 고장 난 기기의 증상과 가설을 대조해 수리 순서를 정하는 데 쓸 수 있다. 다만 증상이 일치해도 고장의 증거는 아니다. 서로 다른 결함이 같은 증상을 낼 수 있고 시뮬레이션에도 한계가 있다.

실행과 조작

macOS와 Linux(X11)에서 OpenGL을 사용해 실행한다. 그래픽·인터페이스 라이브러리인 sokol과 nuklear는 third_party/에 들어 있다. 빌드 명령은 다음과 같다.

make ./c64-hw-sim [program.prg] 

창에는 보드, 모니터, 제어 패널과 오실로스코프가 표시된다. RAM1~RAM8은 각각 바이트의 한 비트를 담는 4164 DRAM이며, VRAM은 2114 컬러 RAM이다. BASIC, KERNAL, CHAR는 ROM이고 PLA는 주소 디코더다. 확대하면 부품 번호와 주소 범위를 확인할 수 있다. 핀 색상은 빨강이 high, 파랑이 low, 노랑이 펄스, 회색이 부동 상태이며, 자홍색은 두 출력이 충돌하는 상태다.

핀을 클릭하면 오실로스코프에 연결하고 부동 상태로 만들거나 GND 또는 +5V에 단락할 수 있다. 칩을 클릭하면 소켓에서 빼고, 저항·페라이트 비드·크리스털을 클릭하면 연결을 끊는다. 제어 패널에는 설정한 고장이 표시되며, 각 항목의 수리 버튼으로 복구할 수 있다. .prg 파일은 프리저 카트리지처럼 DRAM 칩에 직접 기록하므로 보드가 고장 난 상태에서도 불러올 수 있다. 키보드는 일반적으로 입력하며 ESC는 RUN/STOP, PgUp은 RESTORE, TAB은 CTRL, 왼쪽 ALT는 C=에 해당한다.

명령행에서는 창 없이 200프레임을 실행해 화면의 글자를 읽고 그림을 저장하며, U17을 제거한 상태를 지정할 수 있다.

./c64-hw-sim --headless 200 --text --shot out.png --fault U17:removed 

고장 표기는 REF:what 또는 REF.PIN:what 형식이다. 예시는 다음과 같다.

U17:removed   U21.14:gnd   U12.14:vcc   U9.2:open   R51:open   RP4:short 

--at 150:U6.17:open --at 300:repair는 실행 중 부품을 고장 내고 복구한다. --nets는 출력끼리 충돌한 네트를 보고하며, C64HW_TYPE=$'PRINT 1+1\n'은 부팅 후 입력할 문자를 지정한다. C64HW_CHECK=1은 KERNAL의 읽기와 VIC의 메모리 접근을 이상적인 메모리 맵과 대조한다. 그래픽 모드에서 --record 900:DIR --frames 90을 쓰면 900프레임부터 시뮬레이션 프레임 4개마다 창 화면을 저장한다. 위 GIF는 이 기능으로 만들었다.

CHAR ROM(U5)을 소켓에서 뺐다가 다시 끼우는 GIF에는 10 PRINT CHR$(205.5+RND(1));:GOTO 10 미로 프로그램이 나온다. ROM을 빼도 CPU와 RAM, 프로그램은 계속 작동하고 문자 모양만 사라진다. ROM 소켓의 D0 데이터 선을 관찰하면, VIC가 문자 모양을 가져올 때 소켓이 비어 있는 동안 버스가 부동 상태가 되는 것을 볼 수 있다. GIF는 C64 속도로 재생된다.

구현 방식과 한계

tools/kicad2c.py는 bwack의 250407 KiCad 복제본을 C 테이블로 변환한다. 여기에는 부품 216개와 패드, 네트 249개가 담긴다. 각 핀은 네트에 강한 신호나 풀업 같은 약한 신호를 보내거나, 전원 단락을 일으키거나, 아무 신호도 내지 않는다. 가장 강한 신호가 우선하며, 같은 세기의 신호가 충돌하면 이를 경합으로 처리하고 low를 선택한다.

아무도 신호를 보내지 않는 네트는 전하를 유지한 뒤 서서히 변한다. TTL 입력이 연결돼 있으면 수 마이크로초 안에 약 1.4V로, MOS 입력만 연결돼 있으면 1초의 일부 시간 안에 0V 쪽으로 이동한다. MOS 입력은 여기에 잡음을 더해 자체 임계값과 비교하므로 부동 선을 불안정하게 읽을 수 있다. 잡음의 초기값은 고정돼 같은 실행을 재현할 수 있다.

칩별 전원 고장도 모델링한다. VCC가 없으면 칩은 작동하지 않고, GND가 없으면 출력이 high로 부동한다. CMOS 칩은 핀의 보호 다이오드를 통해 유입되는 잔류 전원으로 계속 작동할 수 있다. src/parts.c는 로직 회로, ROM, /RAS에서 행 주소를 래치하고 /CAS에서 열 주소를 래치하는 DRAM, 컬러 RAM, 실제 논리식을 적용한 PLA를 핀 단위로 모델링한다. 6510, VIC-II, CIA, SID는 floooh의 chips에서 가져온 사이클 단위 코어다.

프로그램은 모든 칩의 핀을 시뮬레이션하기 때문에, 원문에 제시된 컴퓨터에서도 실제 속도의 3분의 1에서 절반 정도로 실행된다. Apple M3 Max에서는 C64 속도의 31%, AMD Ryzen AI Max+ PRO 495(Gorgon Halo)에서는 39%, Apple M5 Max에서는 48%다. 따라서 게임용 에뮬레이터는 아니다.

부동 상태와 전원 동작 모델은 대략적인 특성만 반영하며, 임계값·전하 변화 시간·누화 수치는 추정값으로 src/sim.c에 상수로 들어 있다. 비디오 출력, SID 필터, 전원 공급 장치, 도트 클록 PLL은 시뮬레이션하지 않는다. DRAM 셀 불량이나 느린 부품 같은 칩 내부 고장, 두 네트 사이의 브리지는 구현 예정이지만 아직 포함되지 않았다.

프로그램을 만든 antirez는 floooh의 6502, VIC-II, CIA, SID 에뮬레이터에서 아이디어를 얻었다고 밝혔다. 이 칩 코어는 c64-llm에서 가져왔으며 zlib 라이선스를 따른다. 기판 데이터는 bwack의 C64-250407-Replica-KiCad에서 가져왔고 CERN OHL을 따른다. PLA 방정식은 Mark Smith와 Marko Mäkelä가 82S100을 읽어 얻은 자료를 사용했다. 고장 31가지를 실행하는 tests/faults.sh의 각 예상 증상은 시뮬레이터를 실행하기 전에 기록했다.