プログラミングや低レイヤで遊ぶ人

基本的には遊んだことを記事にしていく

ファミコンエミュレータ作り その2

golangによるファミコンエミュレータ作り

完成までのマラソン記事。がんばってやり切るぞい

また、注意点としてこの記事はコードを更新しながら作成していっていくので記事で書いてある内容と実際のコードに差が生まれる可能性はあります。

コード本体         

この記事の内容と最終目標

この記事の内容

ファミコンエミュレータを作成していく過程を記事にしていきます。基本的にはコードの説明なので、コードを眺めながらこの記事を読むのがベストです。

最終目標

本当はマッパー0のカセットが実行できるくらいまで実装するとかなり画面映するのですが、そこまでやると後半は細かい昨日をひたすら足していくだけのつまらない内容になるのでこの記事群での最終目標は下の図のような画面を表示することを目標とします。なお、申し訳ないのですがさすがに著作権的にあれな気がするのでこのromイメージはgithubには上げていません。 f:id:jumdtw:20200506193714j:plain ちなみに、この美少女は「アメイジンググレイス」というゲームのヒロインの一人です。とても面白いゲームなのでおすすめ。
アメイジンググレイスHP

環境

go version go1.13.8 windows/amd64

上記の環境で基本的にはやっていきます。windows以外での動作確認は基本しません。

golangを使う理由が特にあるわけではありません。ただのノリです。(rustやjavascriptで実装している人もいるらしい)






ファミコンへの描画の仕方


ファミコンへの描画の方法はすでに様々な記事で紹介されています。
ただ、具体的な方法で紹介されているものが少なかったのでその辺を複数回にわたって説明できればいいなと考えています。

ちなみに、描画がに関しての情報で参考になったもののリンクを下記に貼ります。

電子書籍「ファミコンゲーム製作入門」
NES研究室 ~グラフィック~
Memory-Mpa of Nes
ファミコンで始める ~ 6502マシン語ゲームプログラミング

ファミコンにはPPUというCPUとはまた別途のグラフィック専用のパーツがくっついています。PPU のVRAMに描画したい情報を書き込むと無事画面に映し出すことができるわけです。しかし、CPUはPPUのVRAMに直接アクセスができません。そのためメモリの $2006に書き込みたいVRAMNのメモリ位置を指定 します。そして $2007に書き込みたい値を書き込む ことでVRAMへの書き込みができます。

・0x3700 ~ : パレット情報。使用する色群を決める。
・0x23c0 ~ : attribute情報。要するに、使用するパレットの指定
・0x2000 ~ : ネームテーブル。CHAROMの内どれを描画するのかを決める。


多分説明を淡々と書いてもわかりづらいと思うので、次回実際に描画してエミュレータに必要な部分を追加していきます。

参考

壁は通り抜けられませんよ ~NES基礎知識 - PPU

ファミコンエミュレータ作り その1

golangによるファミコンエミュレータ作り

完成までのマラソン記事。がんばってやり切るぞい

また、注意点としてこの記事はコードを更新しながら作成していっていくので記事で書いてある内容と実際のコードに差が生まれる可能性はあります。

コード本体         

この記事の内容と最終目標

この記事の内容

ファミコンエミュレータを作成していく過程を記事にしていきます。基本的にはコードの説明なので、コードを眺めながらこの記事を読むのがベストです。

最終目標

本当はマッパー0のカセットが実行できるくらいまで実装するとかなり画面映するのですが、そこまでやると後半は細かい昨日をひたすら足していくだけのつまらない内容になるのでこの記事群での最終目標は下の図のような画面を表示することを目標とします。なお、申し訳ないのですがさすがに著作権的にあれな気がするのでこのromイメージはgithubには上げていません。 f:id:jumdtw:20200506193714j:plain ちなみに、この美少女は「アメイジンググレイス」というゲームのヒロインの一人です。とても面白いゲームなのでおすすめ。
アメイジンググレイスHP

環境

go version go1.13.8 windows/amd64

上記の環境で基本的にはやっていきます。windows以外での動作確認は基本しません。

golangを使う理由が特にあるわけではありません。ただのノリです。(rustやjavascriptで実装している人もいるらしい)

6052cpuの実装

現状のファイル構成はこんな感じです。

C:.
├─FC_CPU
|   ├─emu_CPU.go
|   └─opcmd.go
|
└─FC_APU

ここではCPUのエミュレータの本体を作っていきます。具体的には下記コードのような感じです。

const (
    memCap = 65535
)

type emu struct {
    // A X Y S P
    regi map[string]uint8
    // PC
    regPc uint16
    // memory
    memory [memCap]uint8
}

構造体を使用してエミュレータ本体を作成していきます。 ファミコンレジスタはPCは16bitで、それ以外は8bitです。 また、本来のファミコンのメモリ容量は2kBですがカセットのコード部分は0x8000部分に入ったりと2kBのまま作るとあとあと面倒臭そうだったので0xffffの容量で作成しました。

このCPUエミュレータは下記のコードで命令を実装します。

func (fcEmu *emu) Execute() {
    var opcd uint8 = fcEmu.memory[fcEmu.regPc]
    fcEmu.regPc++
    switch opcd {
    // lda
    case LDAIMM:
        fcEmu.ldaImm()
    case LDAZERO:
        fcEmu.ldaZero()
    case LDAZEROX:
        fcEmu.ldaZeroX()
    case LDAABS:
        fcEmu.ldaAbs()
    case LDAABSX:
        fcEmu.ldaAbsX()
    case LDAABSY:
        fcEmu.ldaAbsY()
    case LDAINDX:
        fcEmu.ldaIndX()
        .
        .
        .

このExecute()をmain文で実行していきます。

func main() {
    var fcEmu = emu{}
    _ = initEmu(&fcEmu)
    fcEmu.Execute()
    debug(&fcEmu)
}

まとめ

今回は単純なCPUエミュレートのため解説は少なめです。おそらく今回の部分はこの記事を読むより実際のコードを見た方が理解しやすいです。そのうち段々とファミコンの仕様を解説しつつコードの説明をしていきます。

親知らずをぬいたはなし

前日まで

顎がいたかったので歯医者に相談したことが発端であった。レントゲンを撮ったところ親知らずが完全にすや~している状態(横向きになっている)であるらしくこのままだと虫歯になったり歯並びに影響すると言われたので、とりあえず片方の親知らずを抜くことになった。

正直なめていた。研究室やバイト先の人に迷惑がかからないようにとあらかじめ施術があると伝えていったのだがみなそろってとても痛いといっていた。しかし、私個人は昔から結構ケガをしていたりしてきたのでまぁ大丈夫だろうと謎の自身があった。調子にのってyoutubeで親知らずの抜歯の動画などを見ていた。

ちなみに、親知らずを抜歯する際は歯のクリーニングが終わって医師の説明を聞いてやっと施術にはいれるらしいので意外と時間がかかる。まだ抜いていない人はまとまった時間がある時に医師に相談した方がいい。(私の場合は3週間もかかった。)

当日

最初の医師の説明で言われたのが私は口のサイズが大きいため比較的簡単とのことだった。早ければ15分で終わると言われた。もはや私は東大に合格して人生すべて安泰だと勘違いしている学生のような心持ちであった。これが地獄の始まりともしらず.....

いざ施術が始まった。実際施術中は全く痛くなかった。もちろん最初の麻酔の注射は痛かったもののこれすらも表面麻酔を塗りたくってもらったのであまり痛くなかったのだ。私は心ルンルンのまま横たわっていたのだ。

しかし

様子がおかしくなったのは開始10分目あたりのことであった。医者から「あれ?ない?」という施術中医師から聞きたくないセリフベスト20に入っていそうなセリフが飛んできたのだ。そこからドリルを口につっこんでいくのだが、いかんせん回数がおかしい(私の知識がないだけで実は普通のことかもしれません)。2~3回くらいかと思ったら5~8回ほどやられた。もはや焦げ臭いのだ。さらに頬を切除する施術なのではと思うほど引っ張られる。

結局1時間10分かかった。その間ほぼずっと口を開けていたのでとても疲れた(医師さんの方が確実に疲れているのは把握しているので悪しからず)。医師の説明曰く私の頬の筋肉が異常らしくなかなか大変だったらしい。さらに、口が横のみならず縦にも広いらしく親知らずまで器具(ドリルなど)が届かなかったらしい。そのために頬を引っ張って無理やり突っ込んでいたらしい。経過を見て1週間後くらいに抜糸をすると言われた。

過程がどうにせよ施術は終わった。麻酔も効いたままであったため痛くなかった。そのためルンルンで帰宅した。 ちなみに、料金は8000円ほどであった。

そして、麻酔がきれた。

痛い。痛すぎるのだ。しかし、いつもの痛みとはわけが違う。痛みの強さが強いのではなく的確にいやな部分が痛くなるのだ。特に意外だったのはのどの痛みであった。イメージでいうと風邪の時、唾すらも呑み込めなくなるあの痛みである。咀嚼できなくなるだろーと予想していたので野菜ジュースなどを準備していたのだがまずそれが飲めないのだ。さらに、耳の周りが痛くなる。耳鳴りのような症状まででてくるのだ。これらの痛みの厄介なところは処方された鎮痛剤ではおさまらないところであった。鎮痛剤が抑えてくれるのは施術箇所の痛みだけであった。その日の終わり頃には肩も痛くなってきた。

2~3日目

私の調べた限りでは、一般的に痛みがピークに達する日である。無論私も例外ではなかった。痛みが増えるというわけではなく、上記の肩の痛み・耳鳴り・のどの痛みなどの症状が悪化していくのだ。頭を使う余裕などが一ミリもなくバイトも研究室も休んだ。かなりの痛手であったがそんなことを言っている余裕がない。とりあえず、症状を早く直すためにのどの痛みをこらえて野菜ジュースやプロテインを飲んで栄養を摂取しストレッチなどの軽い運動をしつつ睡眠をなるべくとった。そのおかげか症状が早くなお(ry

そんなわけがなかった。

まったく治らないのだ。ストレッチなどのおかげで肩・耳の症状が軽くなったのだが、のど・施術箇所の痛みが全くひかないのだ。絶望でしかない。

4~5日目

やっとのどの痛みが引いた。しかし、施術箇所の痛みがまったくひかないのだ。だが、これに対して私は余裕であった。なぜなら施術箇所には鎮痛剤というアイテムがあったからである。飲むと1時間くらいで完全にききはじめ痛みがなくなるのだ。だがついにその時が来てしまった。鎮痛剤が切れたのだ。しかし、時代は2020年。薬局にいって薬剤師さんに相談したところ似た成分の鎮痛剤があり、これで大丈夫だ!!!と華麗にフラグを立てた。飲むととんでもない吐き気に襲われるのだ。具体的には電車やエレベーターに乗れないレベルの吐き気である。それでも無理やり研究室にいきすべての機材をリモートでできるように設定した。自分でもほめてあげた。

6日目

あまりに痛くさすがにおかしいと感じ歯医者にいった。しかし、医師曰くすさまじく順調に傷が治っているとのことであった。ほんとかよと疑問をいだくスキすきもなく抜糸が始まった。治っているのに糸がずっと口にあると衛生的に悪いためらしい。

糸をとった瞬間衝撃であった

これまでの痛みがすべてなくなった(さすがに口の中に違和感はあったが)。どうやら口の痛みの原因は死ぬほどきつく縛られた糸であったようだ。これのおかげで完全に元の調子に戻り元気になった。原因が自分になくてほんとによかったと感じている。痛みの原因が医師にあったとも思わない。実際傷はちゃんと治っているためである。

まとめ

これが私の親知らず抜歯の全治療の過程である。この一週間は何もできなかったといっても過言ではない。そして常に痛みが付き添うためとにかくストレスがたまる。これから抜く人はぜひ周りの人に相談をし十分に時間をとってほしい。頼りになる人が近くにいるとなおよし。

ちなみに、私はまだ片方なのでこの絶望一週間がもう3回まっている。