Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
ファミコンに思いを馳せる〜エミュレータ自作を添えて〜
Search
noharu36
December 01, 2025
Programming
0
15
ファミコンに思いを馳せる〜エミュレータ自作を添えて〜
noharu36
December 01, 2025
Tweet
Share
More Decks by noharu36
See All by noharu36
検証!会津は本当に地盤が硬いのか?
noharu36
0
13
自作オブジェクトストレージをRustで
noharu36
0
39
shell自作した話
noharu36
0
21
Rustを布教したい
noharu36
0
17
neofetchよ、永遠に
noharu36
0
20
ISSの軌道計算をRustで
noharu36
0
17
Other Decks in Programming
See All in Programming
社内規程RAGの精度を73.3% → 100%に改善した話
oharu121
13
7.8k
ふつうの Rubyist、ちいさなデバイス、大きな一年
bash0c7
0
740
Claude Code の Skill で複雑な既存仕様をすっきり整理しよう
yuichirokato
1
320
Codexに役割を持たせる 他のAIエージェントと組み合わせる実務Tips
o8n
3
1.1k
AI活用のコスパを最大化する方法
ochtum
0
130
DevinとClaude Code、SREの現場で使い倒してみた件
karia
1
980
「やめとこ」がなくなった — 1月にZennを始めて22本書いた AI共創開発のリアル
atani14
0
360
CSC307 Lecture 15
javiergs
PRO
0
230
Go 1.26でのsliceのメモリアロケーション最適化 / Go 1.26 リリースパーティ #go126party
mazrean
1
360
AI時代のソフトウェア開発でも「人が仕様を書く」から始めよう-医療IT現場での実践とこれから
koukimiura
0
140
encoding/json/v2のUnmarshalはこう変わった:内部実装で見る設計改善
kurakura0916
0
350
CSC307 Lecture 12
javiergs
PRO
0
460
Featured
See All Featured
How Software Deployment tools have changed in the past 20 years
geshan
0
32k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.6k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
67
The Illustrated Guide to Node.js - THAT Conference 2024
reverentgeek
1
290
Producing Creativity
orderedlist
PRO
348
40k
Navigating the Design Leadership Dip - Product Design Week Design Leaders+ Conference 2024
apolaine
0
220
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
150
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Mobile First: as difficult as doing things right
swwweet
225
10k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
120
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.2k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
770
Transcript
ファミコンに思いを馳せる 〜エミュレータ自作を添えて〜 学部2年 harukun
自己紹介 • 名前: 能島明希 • ハンドルネーム: harukun • 出身: 広島->岡山->大阪->東京->会津 • 技術: フロント(React+TS), バックエンド(Rust,
Go勉強中), その他(Rust, Haskell勉強中), Rust(Rust) • 好きなもの: ゲーム、タバコ、炒飯、 Rust、Neovim • 落とした単位数: おそらく同期内1位 • Twitter: https://twitter.com/pieceofharuki • Blog: https://zenn.dev/haru_blog
ファミコンとは
基本情報 • 1983年7月15日発売 正式名称ファミリーコンピュータ • 累計出荷台数6000万台 • 当時の家庭用ゲーム機 脅威の80%シェア • 世帯普及率25% 小中学生がいる家庭のほとんど •
スーパーマリオブラザーズ 世界売上 4000万本 2020年にあつ森に抜かれるまで 30年以上国内売上1位 今でも歴代世界売上本数6位
技術 • CPU Ricoh 2A03 MOS 6502(Apple Ⅱに搭載)をカスタマイズしたもの 当時よく使われていたz80に比べクロック数は劣るが、チップ面積が1/4でコストを削減できた 当時日本ではほぼ無名でリバースエンジニアリングされづらかった(ナムコは執念で解析した)
• ROM USBメモリとは違う メモリにアクセスするようにCPUから直接アクセスできて早い(カセットの中身をメモリに展開する必要がない) キャラクターROMとプログラムROMに分かれている • APU(オーディオプロセッシングユニット) CPUに内蔵されている 主にパルス波・三角波・ノイズで構成されている • PPU(ピクチャープロセッシングユニット) Ricoh 2C02(最初期) Apple Ⅱ
ファミコンエミュレータ自作してみた
Why • Rustでものづくりしたかった • 低レイヤなことにも少し興味があった • ちょうどGWだから何か作ろうと思った • 9月ごろに一回挑戦して失敗したから再挑戦することにした •
Rust書きたかった
技術スタック
実装の流れ 1. NES(ファミコンのこと)についておおまかに理解する 2. アセンブラの復習 3. CPUの実装 4. BUSの実装 5.
テスト、そして圧倒的デバッグ 6. PPUの実装 7. コントローラーの実装 8. (スクロールの実装) 9. APUの実装 //まだ!
ファミコンについて大まかに理解する • アーキテクチャ OSがないのでアプリケーション層が直接ハードウェアと通信する • CPUとPPUは直接カセットに接続できる • カセットを挿入するとCPUがプログラムROMに、PPUがキャラクターROMに接 続される •
CPUのメモリは2KiB(2048B)しかなかった • CPUの内部にAPUが実装されている • CPUにはWRAMという2KiBのメモリが接続されている • PPUにはVRAMという背景情報・スプライト情報などが格納される 2KiBのメモリ が接続されている • CPUは直接VRAMにアクセスできないが、PPUのレジスタを介してアクセスで きる
https://qiita.com/bokuweb/items/1575337bef44ae82f4d3#%E7%B0%A1%E6%98%93%E3%83%8F%E3%83%BC%E3%83%89%E3%82% A6%E3%82%A7%E3%82%A2%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E5%9B%B3
CPUの実装 • アドレスによってどこにアクセスできるか決まる • メモリアクセスは比較的遅いので非常に速くアクセスできるレジ スタと呼ばれる内部メモリ スロットがいくつかある ◦ レジスタのみにアクセス ◦
RAMの最初の255バイトへのアクセス • 上記に注意しながら約150の命令を実装する(白目)
こんな感じで命令を羅列して こんな感じで命令を実装して こんな感じで分岐を書く
これでようやくHello Worldができた
テスト テスト用のROMを読み込んで実行する diffコマンドを用いて実行ログとテスト用の ログを比較する (左が実行結果 右がテスト用ログ 左右が等しくなれば正常) すると実装されてない命令がいくつか (110個)あることがわかる これらは非公式命令と言われていて、 6502には公式に実装されていなかったが多くのゲームで使われている命 令たちなので、追加で全部実装する
()
こんな感じで命令を羅列して こんな感じで命令を実装して こんな感じで分岐を書く(ヤケクソ)
PPUの実装 • レジスタ CPUとの接続に使う( CPUアドレス空間の0x2000~0x2007) • 内部メモリとしてスプライトの状態を保持する OAMを持つ(256B) • 描画サイクル
◦ PPUは1秒間に262ラインレンダリングする ◦ NESの解像度は320 x 240 ◦ よって262-240=21ラインは画面に映らない ◦ 241ライン目に入ると VBlankというNMI割り込み命令が CPUに送 られる ◦ この間PPUのメモリは変更されないので CPUから自由にアクセス できるため次のフレームのために画面の状態を更新する
だるかったこと PPUは1クロックサイクルで1ドット描写する PPUはCPUの3倍高速なのでCPU1クロックサイクル=PPU3クロックサイクル PPUとCPUのクロックサイクルを合わせてあげないと画面が崩れてしまう 1ラインごとのPPUのクロックサイクルは341 1フレーム毎に341x262=89342PPUクロックサイクルになる CPUは29780CPUクロックサイクルごとにNMI割り込みを受ける
• まずCPUの命令毎にクロックサイクルを定める • PPUのtick関数に3倍したものを引数として渡す • cyclesが341を超えた時にscanlineをインクリメントし、 scanlineが241になった時にCPUにNMI割り込み命令 を送る • CPUはNMI割り込み命令を受け取ると現在の命令の実
行を終了し次フレームの画面の描写の準備に入る
スクロール 長くなるのでカット! ファミコンには画面の状態を保持する VRAMと呼ば リがあって、サイズは2 KiB。1画面を表示するのに モリは1KiBなので2画面分を割り当てられる。まず zero hit flagの設定をする。sprite
zeroを画面の特 置(X, Y)に配置し、sprite zero hit flagが0から1に と、CPUはPPUが[0..Y]スキャンラインのレンダリン しYスキャンライン上でXピクセルのレンダリングが ことを示す。垂直または水平ミラーリングを実装し viewportを動かしていった分を shift_x, shift_yとお 256-shift_x, 240-shift_yを2つ目の画面のサイズ 定しフレーム毎に更新することで、静的な背景を動
できたもの
まとめ • 当時、ファミコンの開発に携わってた人たちはほんとにすごい • エミュレータの実装を通して、少しだけでも当時のエンジニアたちの気持ちを理解することができた • メモリアクセスやアセンブラについて詳しくなれた • エミュレータ自作とは結局小さなコンピュータを自作すること。次は OS自作に挑戦したい。
• 最後まで完成させることはできなかったけど、今までやったことがない低レイヤなことができてよかった
おまけ セキュキャンに申し込みました。 今回の開発で低レイヤにもっと興味が沸いたので OS自作や探査機自作ゼミに参加したい。 5/20が応募課題の締切なので1日8時間ほど取り組めばなんとか終わるだろうという計算 ...