# nesformer: 언어 모델 안에서 NES 게임 실행하기
# nesformer: running NES games inside a language model

- Site: https://select1.dev/2026-11-01 (English), https://select1.dev/ko/2026-11-01 (Korean)
- Entry: 022
- Published: 2026-11-01 (KST). Launch date: 2026-10-31
- Pick: nesformer <https://github.com/dbreunig/nesformer> (source: Show HN)
- Verified: ran
- What: nesformer 는 NES 게임을 언어 모델로 실행하는 프로덕트다. 제작자는 NES 의 CPU 회로를 학습 없이 Qwen3.5 모델의 가중치로 컴파일했다.
- What (en): nesformer is a product that runs NES games inside the weights of a language model. It compiles the NES CPU into Qwen3.5 weights without any training.
- Why: 오늘의 픽으로 선정한 이유는 모델이 오차 없이 계산하는지 검증할 수 있게 하기 때문이다.
- Why (en): It is today’s pick because one command compares the model’s output with a reference CPU’s.
- Verdict: 작동한다. 모델이 생성한 토큰 약 70,000개가 기준 CPU 의 실행 기록과 같았다.
- Verdict (en): It works. About 70,000 tokens from the model matched the reference CPU’s log.
- Tags: nes, emulator, transformer, compiler, qwen, python

## Checked against the README

- [pass] 모델이 생성한 실행 기록은 기준 CPU 의 기록과 같다(The weights, free-running, generate traces identical to the reference CPU’s) — check 명령으로 Thwaite 에서 토큰 20,000개, nestest 에서 토큰 50,001개를 생성해 저장소의 기준 6502 구현과 대조했다. 토큰과 화면 프레임(5개, 81개)이 모두 같았다
- [pass] CPU 코어 하나에서 초당 약 1,650 토큰을 생성한다(about 1,650 tokens/s on one CPU core) — check 를 두 번, run 을 한 번 실행했다. 도구가 출력한 생성 속도는 초당 1,469~1,719 토큰이었다. 이 속도에는 가중치를 불러오는 시간이 포함되지 않는다. run 의 CPU 사용 시간(user, 104초)이 경과 시간(106초)과 비슷해 코어 하나만 사용한 것으로 판단했다
- [pass] 아무도 이 가중치를 학습하지 않았고, 컴파일러가 모든 값을 계산했다(Nobody trained these weights; a compiler computed every one) — build --out 으로 회로에서 가중치 파일을 다시 만들었다(18초). 새 model.safetensors 의 SHA-256 이 배포된 파일과 같았다

## Measured

- Thwaite 120프레임(실제 NES 에서 2.0초) 실행. 4코어 컴퓨터, 버튼 입력 없음: 102초, 토큰 175,511개(초당 1,719개) (python -m nesformer run roms/thwaite.nes --frames 120 --gif thwaite.gif 이 출력한 생성 시간과 토큰 수. time 의 경과 시간은 106초)

## 한국어

## 무엇이 문제인가

언어 모델이 프로그램을 오차 없이 실행하려면, 모델이 그 프로그램과 똑같이 계산하도록 가중치를 정확히 정해야 한다.

보통 언어 모델의 가중치는 데이터로 학습해 만든다. 학습한 모델은 잘못된 결과를 낼 수 있다. 가중치를 읽어서는 모델이 어떤 계산을 하는지도 알 수 없다.

## 어떻게 해결했나

nesformer 는 2026년 10월 31일 Hacker News 에 Show HN 글로 올라왔다. nesformer 는 가중치를 학습하지 않고 컴파일러로 계산한다. NES 의 CPU 와 내장 RAM 2 KB, 게임 카트리지의 프로그램 ROM 이 Qwen3.5 구조의 모델 안에 들어 있다.

게임을 실행하면 모델은 CPU 의 실행 기록을 토큰 하나씩 예측한다. 모델은 CPU 명령어 하나를 실행할 때 대개 토큰 하나를 생성한다. 게임 코드에서는 명령어 하나에 토큰이 평균 1.1~1.3개 나온다. 화면 그리기와 컨트롤러 입력, 인터럽트는 별도의 호스트 프로그램이 처리한다. 호스트는 CPU 의 레지스터와 메모리에 직접 접근하지 않고, 모델이 생성한 실행 기록만 읽는다. `check` 명령은 같은 게임을 모델과 기준 CPU 에서 함께 실행하고, 토큰이 처음 달라지는 곳에서 멈춘다. 기준 CPU 는 NES 의 6502 CPU 를 Python 으로 구현한 프로그램이다.

## 무엇이 다른가

가중치를 만드는 방법이 다르다. nesformer 는 컴파일러로 CPU 의 회로를 가중치로 변환한다. 컴파일한 가중치는 Hugging Face 의 표준 Qwen3.5 모델 파일이다. README 에 따르면 별도 코드 없이 transformers 라이브러리로 불러올 수 있다. 파라미터 466,647,616개 가운데 0 이 아닌 값은 9,340,331개다. 그래서 933 MB 인 가중치 파일을 zip 으로 압축하면 3.3 MB 가 된다. Qwen3.5 의 Gated DeltaNet 층은 토큰마다 상태 행렬을 갱신한다. 이 행렬의 행 하나가 메모리 한 칸이 된다. 카트리지 ROM 과 RAM, 레지스터가 모두 이 행렬에 저장된다. 오픈소스 프로젝트 Qwenputer 가 이 컴파일러 chipformer 를 만들어 CHIP-8 과 RISC-V CPU 를 Qwen3.5-4B 의 가중치로 컴파일했다. nesformer 는 같은 컴파일러로 NES 의 CPU 를 층 8개짜리 Qwen3.5 모델에 컴파일했다. 트레이드오프는 실행할 수 있는 게임이 제한된다는 점이다. 프로그램 ROM 을 모델 안의 고정된 32 KB 테이블에서 읽기 때문에, 카트리지에 매퍼 칩이 있는 큰 게임은 실행되지 않는다.

다만 실제 NES 보다 느리다. README 에 따르면 실제 NES 와 같은 속도로 실행하려면 초당 약 700,000 토큰이 필요하다. 제작자의 컴퓨터에서는 코어 하나로 초당 약 1,650 토큰을 생성했다. 게임 코드에는 화면 갱신을 기다리는 루프가 있다. README 에 따르면 호스트 프로그램은 이 루프의 반복을 건너뛰어 토큰 수를 2.6~4.2분의 1 로 줄인다. 이렇게 줄여도 실제 NES 보다 150~290배 느리다.

## 어떻게 만들었나

- 저장소의 커밋은 2026년 10월 30일의 첫 공개 커밋 하나다. AI 도구와 함께 작성했다는 Co-authored-by 트레일러는 없다.
- 제작자는 Qwenputer 의 컴파일러 chipformer 를 MIT 라이선스에 따라 저장소에 포함했고, 회로와 가중치를 만드는 코드 일부는 Qwenputer 의 코드를 수정해 작성했다.
- 제작자는 README 에 검증을 네 단계로 기록했다. 기준 CPU 는 다른 6502 에뮬레이터와 대조하고, CPU 시험용 ROM nestest 의 공식 로그와도 대조했다. 회로와 가중치 파일은 기준 CPU 와 대조했다.

## 실행해 보니

README 의 명령을 따라 4코어 컴퓨터에서 GPU 없이 실행했다.

1. 설치. 저장소에 든 nesformer-weights.zip(3.3 MB)을 풀자 가중치 파일이 933 MB 가 됐다. SHA-256 이 저장소의 값과 같았다. `pip install numpy scipy numba pillow` 는 14초 만에 끝났다.
2. 대조. NES 게임 Thwaite 로 `check roms/thwaite.nes --tokens 20000` 을 실행했다. 가중치를 불러오는 시간을 포함해 16초 만에 끝났다. 도구가 출력한 생성 속도는 초당 1,469 토큰이었다. 모델이 생성한 토큰 20,000개와 화면 5프레임이 기준 CPU 의 결과와 같았다. nestest 로도 같은 방식으로 대조했다. 가중치를 불러오는 시간을 포함해 34초가 걸렸다. 토큰 50,001개와 화면 81프레임이 같았다.
3. 게임. `run roms/thwaite.nes --frames 120` 을 실행했다. 모델은 102초 동안 토큰 175,511개를 생성했다. 초당 1,719개다. 120프레임은 NES 에서 2.0초이므로 실제 게임기보다 51배 느린 셈이다. 버튼을 누르지 않아 게임 시작 전 화면까지만 진행됐다. 프레임당 토큰은 약 1,460개였다. README 에 따르면 Thwaite 를 600프레임 실행했을 때는 프레임당 약 3,200개였다. 프레임마다 0.4~2.4초가 걸렸다.
4. 재빌드. `build` 로 회로에서 가중치 파일을 다시 만드는 데 18초가 걸려, README 에 적힌 약 10초보다 길었다. 새 파일의 SHA-256 은 배포된 가중치 파일의 값과 같았다.

```
frame 120/120  175,511 tokens  1,719 tok/s  1.6s/frame
175,511 tokens in 102s (1,719 tok/s), 120 frames, 3,573,681 CPU cycles (2.0s of NES time)
```

## 확인하지 못한 것

- 게임 진행. README 의 예시 명령에 있는 버튼 입력 순서로 Thwaite 를 600프레임 실행해 게임 화면까지 확인하자. README 에 따르면 600프레임에 약 25분이 필요하다.
- 표준 transformers 실행. torch 를 설치하고 `--engine hf` 로 같은 가중치를 실행해 보자.

## 판정

작동한다. 모델이 생성한 토큰 약 70,000개가 기준 CPU 의 실행 기록과 같았다. 다만 실제 NES 에서 2초 분량을 실행하는 데 102초가 걸렸다. 언어 모델 안에서 프로그램이 오차 없이 실행되는 과정을 직접 확인하고 싶은 경우에 써 볼 만하다.

### 용어

- NES: 닌텐도의 가정용 게임기다. 일본에서는 1983년 패미컴으로 나왔고, NES 는 1985년부터 북미에서 쓴 이름이다. CPU 는 6502 를 바탕으로 만든 칩이다.
- 인터럽트: CPU 가 하던 일을 잠시 멈추고 정해진 코드를 먼저 실행하게 하는 신호다. NES 는 화면을 한 장 그릴 때마다 CPU 에 이 신호를 보낸다.
- Gated DeltaNet: 언어 모델 층의 한 종류다. 앞의 토큰을 모두 다시 참조하는 대신 고정된 크기의 상태 행렬에 앞의 내용을 저장하고, 이 행렬을 토큰마다 갱신한다. Qwen3.5 모델에 들어 있다.
- 매퍼: NES 카트리지 안에서 CPU 가 읽을 ROM 영역을 바꿔 주는 칩이다. 32 KB 보다 큰 게임은 이 칩으로 ROM 의 여러 부분을 번갈아 읽는다.

## English

## The problem

A language model can run a program without error only if its weights encode the program’s computation exactly.

Language model weights are usually learned from data. A trained model can give a wrong result, and reading its weights does not tell you what it computes.

## How it solves it

nesformer was posted on Hacker News as a Show HN on October 31, 2026. It computes its weights with a compiler instead of training them. A model with the Qwen3.5 architecture holds the NES CPU, its 2 KB of work RAM and a cartridge’s program ROM.

When you play a game, the model predicts the CPU’s execution log one token at a time. One CPU instruction usually becomes one token, and game code averages 1.1 to 1.3 tokens per instruction. A small host program draws the screen and reads the controller. It also sends the CPU an interrupt for each new frame. The host never looks at the CPU’s registers or memory directly. It reads only the log the model outputs. The `check` command runs a game side by side on the model and on a reference CPU. It stops at the first token that differs. The reference CPU is a 6502 emulator written in Python.

## What is different

The weights are made differently. In nesformer, a compiler turns the CPU’s circuit into weights. The result is a standard Qwen3.5 model folder for Hugging Face. According to the README, the transformers library loads it without custom code. Only 9,340,331 of its 466,647,616 parameters are nonzero, so the 933 MB of weights zip to 3.3 MB. The Gated DeltaNet layers in Qwen3.5 update a state matrix at every token, and each row of that matrix becomes one memory cell. The cartridge ROM, RAM and registers all live in these rows. Another project, Qwenputer, built the compiler and used it to put CHIP-8 and RISC-V CPUs into Qwen3.5-4B. nesformer uses the same compiler to put the NES’s 6502 CPU into an 8-layer Qwen3.5 model. One limit is that bigger games do not run. The model reads program ROM from a fixed 32 KB table, but their cartridges carry a mapper chip that swaps ROM regions.

It is also slower than an actual NES. According to the README, matching an actual NES would take about 700,000 tokens per second. On the maker’s computer, it generated about 1,650 tokens per second on one CPU core. The host skips repeated iterations of the loop where the game code waits for the next frame. This cuts the token count by a factor of 2.6 to 4.2. According to the README, nesformer runs 150 to 290 times slower than the console overall.

## How it was built

- The repository has one commit, the first public release on October 30, 2026. The commit has no Co-authored-by trailer for an AI tool.
- It includes Qwenputer’s compiler, chipformer, under the MIT license. Parts of the circuit and weight code were adapted from Qwenputer.
- The maker records checks at four levels in the README. The reference CPU was compared with another 6502 emulator and with the official log of nestest, a ROM for testing the CPU. The circuit and the weights were compared with the reference CPU.

## Running it

I followed the README’s commands on a 4-core computer without a GPU.

1. Install. Unzipping nesformer-weights.zip (3.3 MB) from the repository gave a 933 MB weights file. Its SHA-256 matched the value in the repository. `pip install numpy scipy numba pillow` finished in 14 seconds.
2. Comparison. I ran `check roms/thwaite.nes --tokens 20000` with Thwaite, an NES game. It finished in 16 seconds including loading the weights, and the tool reported 1,469 tokens per second. The 20,000 tokens and 5 frames from the model were identical to the reference CPU’s. With nestest, the check took 34 seconds including loading the weights, and 50,001 tokens and 81 frames were identical.
3. Game. `run roms/thwaite.nes --frames 120` generated 175,511 tokens in 102 seconds. That is 1,719 tokens per second. On an NES, 120 frames take 2.0 seconds, so this was 51 times slower than the console. I pressed no buttons, so the run covered only the screens before play starts. It took about 1,460 tokens per frame, less than half of the README’s 600-frame Thwaite run (about 3,200). Each frame took 0.4 to 2.4 seconds.
4. Rebuild. The `build` command rebuilt the weights file from the circuit in 18 seconds. The README says about 10 seconds. The new file had the same SHA-256 as the shipped weights.

```
frame 120/120  175,511 tokens  1,719 tok/s  1.6s/frame
175,511 tokens in 102s (1,719 tok/s), 120 frames, 3,573,681 CPU cycles (2.0s of NES time)
```

## Not checked

- Playing the game. Run Thwaite for 600 frames with the button script from the README’s example command and check the game screens. The README says this takes about 25 minutes.
- The unmodified transformers library. Install torch and run the same weights with `--engine hf`.

## Verdict

It works. About 70,000 tokens from the model matched the reference CPU’s log. But it took 102 seconds to run what an NES runs in 2 seconds. It is worth trying if you want to see a program run without error inside a language model.

### Terms

- NES: Nintendo’s home video game console, sold in North America from 1985. It first came out in Japan in 1983 as the Famicom. Its CPU is based on the 6502.
- interrupt: A signal that makes the CPU pause its current work and run a set piece of code first. The NES sends one to the CPU for every frame it draws.
- Gated DeltaNet: A language model layer that remembers earlier input by updating a fixed-size state matrix at every token, instead of looking back at every earlier token. Qwen3.5 models include it.
- mapper: A chip in an NES cartridge that swaps which part of the ROM the CPU sees. Games bigger than 32 KB use it to reach the rest of their ROM.

## Launches the same day

- nesformer <https://github.com/dbreunig/nesformer> (Show HN, 281): NES 의 CPU 를 학습 없이 Qwen3.5 모델 가중치로 컴파일한 프로젝트. 모델이 게임 코드를 실행한다.
- TNG: Episodle <https://tng.episodle.com/> (Show HN, 228): 스타 트렉 TNG 에피소드 맞히기 게임. 패트릭 스튜어트를 기리는 뜻으로 올렸다.
- xarray-sql <https://github.com/xqlsystems/xarray-sql/blob/6debe2495dcb4e8fac20ab97df5b89baae2a31a6/benchmarks/ml/01_attention.py> (Show HN, 26): Xarray 배열 데이터용 SQL 라이브러리. 약 25줄의 SQL 에서 FlashAttention 커널을 자동으로 도출한 예제를 소개했다.
- Spinf-serve <https://github.com/spinfinc/spinf-serve> (Show HN, 22): GPU 한 장용 분류 추론 서버. 내용을 한 번 읽고 여러 질문의 답을 확률로 낸다.
- bootgpt <https://github.com/kerlenton/bootgpt> (Show HN, 17): 부트 섹터 언어 모델. 512바이트 어셈블리가 11.5 KB 모델을 불러 가짜 Linux 부팅 로그를 생성한다.
- dsh-superagent-prototype <https://github.com/deepseek-ai/dsh-superagent-prototype> (GitHub, 1937): DeepSeek 의 한 팀이 공개한 코딩 에이전트 연구 시제품. GitHub 저장소 하나를 지켜보며 먼저 일을 찾아 한다.
- hop <https://github.com/Arjun-Ingole/hop> (GitHub, 649): Linux 설치 도구. USB 메모리 없이 Windows 옆에 Linux 를 설치한다.
- sapper-v2 <https://github.com/N1nEmAn/sapper-v2> (GitHub, 335): 자동 모의 해킹 에이전트. 지휘하는 AI 가 작업 에이전트 여러 개를 움직인다고 소개한다.
- SKI <https://www.producthunt.com/products/ski> (Product Hunt, 203): 음성 코딩 도구. 말로 코딩 에이전트를 다룬다고 소개한다.
- Specsight <https://www.producthunt.com/products/specsight> (Product Hunt, 187): 제품 관측 도구. AI 로 빠르게 출시하는 팀을 위한 것이라고 소개한다.
- telemetry.dev <https://www.producthunt.com/products/telemetry-dev> (Product Hunt, 173): AI 에이전트용 LLM 관측 도구.

## Getting started

- Steps: git clone https://github.com/dbreunig/nesformer && cd nesformer ; unzip nesformer-weights.zip ; pip install numpy scipy numba pillow ; python -m nesformer run roms/thwaite.nes --frames 120
- Needs: Python 3.11 이상. GPU 는 필요 없다, 디스크 약 1 GB(압축을 푼 가중치 파일이 933 MB 다)
- Cost: MIT, 무료.
- Note: README 에 따르면 매퍼 칩이 없는 카트리지 게임만 실행된다. 저장소에는 재배포가 허용된 ROM 세 개(nestest, Full Game, Thwaite)가 들어 있다.
