image

パッド入力部分を書いたので、動くゲームも出てきました。といってもまだほとんどのゲームが動かないんですけど。画面は ブルジョアソフトウェア研究所 さんのTkShoot 1.00が動作している様子です。

さて、ここまできたので基本的にはこの企画も終了かなー、という感じがします。目的はPythonのパフォーマンスについて知ることだったので。

作成の過程でかなりPythonのパフォーマンス関連について勉強ができてよかったと思います。

速度

サウンドは作っていないので、それを除くと1frameだいたい0.4秒弱くらいで動きます(もちろんpsycoを導入して)。変にベタ書きしたりはしていません。わりとメソッドはちゃんと分割しています。ただ、LDA $ssss(absolute addressingのLDA)だけ、実行回数が多いので完全にベタ書きしました。

んで感じたのは

  • プリプロセッサでマクロを使えばそこそこ実用的な速度になりえるのではないか
  • bytecodehacks でインライン化すれば結構いけるんじゃないか。ただし、bytecodehacksがオブジェクトのメソッドには対応していないので、classを使わずに書くことになる。
  • 部分的にCで拡張モジュールを書けば、わりといけそう

ってことでしょうか。

まぁただ、JAVAとかC系全く分かりません><っていう人以外は、素直にC系かJAVAで書いたほうがいいと思います。

高速化のためにオブジェクトのプロパティをローカルにだしたり

read = self.memory.read
write = self.memory.write
# .
# .
  for i in xrange(foo):
    code = read(addr)
    # .
    # .
    # .

するので、無駄に行数も増えますし、ぶっちゃけ読みにくいです。それでも普段使い慣れてるLLで書けるってのは大きな利点だとは思います。

10年くらいして、マシンがもっと速くなることに期待しましょう、ということで(笑

その他雑感

現時点でも単純なゲームくらいなら、そこそこ動くのでコンピューターの仕組みの基礎を学ぶには、もしかしたらLLでエミュレータってのはいいかも。当然ですけど、デバッグの段階ではアセンブリ言語を書くことになりますし、そのアセンブリ言語の内容も完全に自分で処理するわけですから、単に本で読むよりは格段CPUやメモリについて詳しくなれると思います。ただ、CPUの仕組みを勉強しながら書くのはきついものがあるかもしれませんが・・・

他の利点としては「俺エミュレータ書いたんだぜ」と自慢できる(笑)、自分の書いたエミュレータでゲームが動くと結構感動できる、というくらいでしょうか。


というわけで、とりあえず動くようになりました。今のところソースをアップする気はないです。(してもほとんどのゲームは動かないし意味無い)

確実にいないと思いますが、もし、「俺もLLでエミュレータ書いてみるんだぜ!だからお前のしょーもないソースも参考にしてやるから見せるんだぜ!ついでにエミュってどうやって作るのか教えるんだぜ!」というような方や「おめーソースがないのに信用できるか!」という方がおられましたら、この記事のコメント欄やはてブなんかのコメントに、「うp」とか書いてください。適当にソースまとめてうpして、それをネタに簡単なエミュの書き方でも記事にします(笑

まぁとにかく書いてて楽しかったです。チャレンジ精神旺盛な方、そして時間があまっている方は是非LLでエミュにチャレンジしてみてください。

#追記  アップしました。コチラの記事へドウゾ。

PythonによるNESエミュレータ開発5


時間があればちょっとずつ続けてます。

とりあえず画面がでるようにはなりました。速度は全然追いつかないですけど。

image

CPU

基本的には変化なし。細かいバグが多くて大変・・・・

わずかでも速くしたいところなので、あまり構造を壊さず速度を上げられないかな、と思ってPrefetch cueを実装してみました。Prefetch cueはCPUの非常に基本的な最適化で、基本的故に単純、実装しても負荷になることはないだろう、ってことですな。

エミュレーターでは(とくにPythonでは)ハードウェアでいうメモリが遅いうんぬんとは別の理由で、メモリアクセスはかなり重い処理になります。

def memory(self, addr):
  if addr < "RAMの範囲":
    self.ram[addr]
  elif addr < "メモリマップドIOの範囲":
    self.io.read(addr)
  #else:
  # .
  # .
  # .

さらにページングされている場合、C言語ならポインタでいけるんですけど、Pythonではそうはいかないので、いちいち長ったらしく書くか、ページング用にメソッドを書いてそれをはさむことになります。

そう、関数の呼び出しが非常に多い部分なのです。実際、profileモジュールでデータを取ってみてもメモリ読み込み書き込みが結構なウェイトをしめてました。

そこでPrefetch用のクラスを作って、別スレッドで現在のPC+いくらかをとるようにしてみました。これは現在のオペコードを実行している間に実行されます。これで次のオペコードを実行する前にオペコードとオペランドを取得でき、メモリ読み込み関数を呼ぶ回数が減ります。ただし、本物のPrefetch cueと同じでジャンプ命令が多いとあんまり効果がありません。

Prefetch-cueを入れてみると、まぁコードの内容によりますが、psycoを入れて1frame 0.075くらいまではいきました。PPUをいれると全然なんですけど(笑

PPU

なんとか表示できるまでにきました。正直つらいです(笑 特にスクロールに関しては loopyの文書 の文書が重要、ということをしらなかったのではじめはサッパリでした。

描画部分は pygame です。pygameで描画する場合、更新したRectだけupdateするってのが常套手段なわけですが、エミュの場合はどうも・・・。というわけで今は毎回全体を描画しています。これも結構重い処理になるなあ。

ほとんどスクロールしないゲームの場合、もしかしたら32x32くらいに区切ってスプライトが動いたところだけ更新するようにしたら、結構軽いのかもなあ。


というわけで、PPUをつめてパッド入力あたりを書けばマッパー0のゲームなら動き出しそうな感じがします。ちなみにマッパーは全然です。とりあえずPythonで書いてみることが目的なので実際に使うことは想定して無いですし。

卒論の試問会も終わり、家探しの旅も終わり、つかの間の落ち着きが戻ってきました。なんか資格とかをとらないといけないらしいので、それをちょっとずつ勉強しつつ、こっちもちょっとずつ進めていきたいなーと思ってます。


そういえば、こういうサイトに定番っぽい開発環境を書いたのがないので、自己紹介?も兼ねて晒してみます。

開発はだいたいWindows上のvmware(Debian)でやってます。ただし、そこは定番どころばっかりなのでパス。まぁvim+screen+zshです。puttyでつないでますよ。sambaでマウントしてますよ。ええ。それぞれ結構設定しまくっていて、グローバルなSVNサーバーにおいてあります。

Windowsでの開発環境

あんまりWindowsは好きではないけど、Macよりは好きだったりする。というわけでWindows。普段使いのOSでもあるので、主に自分用の小物を書くことが多いです。怠け者なので、自動化できるものはすぐプログラムに置き換えちゃいます。でも言語は結構様々。もとから言語にこだわらず、一番適しているものを使う主義なので小物が多いにもかかわらず、言語は結構多いのかも。

今のところ、だいたい

  • それなりのGUIが必要なアプリ:Delphi6
  • 一枚ウインドウがあるくらいのGUIアプリ:Python(wxWidgets)
  • GUIがなく、立ち上がりの速さや軽さが欲しいもの:C(MinGW)
  • それ以外の小物:Python

という感じで適材適所。

Linuxではまったく定番な感じ(定番が自分にしっくりきた)だったけど、Windowsにはキーボード派の定番ってのは少ない気がするので、結構独特なのかも。方針は

  • キーボードで操作しやすいように。
  • なるべくlinuxと同じような感覚(←これ重要)で。

感覚なので一緒じゃなくてもいいのです。

gvim

開発はほとんどこいつです。Delphi以外は。Linuxのvimと同じ設定ファイルを共有してます。俺はvimがなくちゃ生きていけない人間なので、USBメモリにいれてもち運べるようにしてあります。

Firefox

ブラウザはこいつ。ただし PortableFirefox です。これもUSBメモリにいれて持ち運べるように。学校にいってもUSBメモリをさすだけで普段の環境。拡張も結構つっこんでます。

cltc

タスク切り替えが便利になるソフト。こんな感じで表示されます。インクリメンタル検索での選択や、カーソルキーでの選択ができます。

image

windowsでタスク切り替えというと`Alt+TAB`ですが、これ非常に使いづらい。そこでこのソフト。ここでキモになるのがキー設定で

  • Ctrl+Shift+z で起動
  • Ctrl+jCtrl+k でタスクを選択

という風に設定しています。俺と同じLinux開発環境の人は分かるでしょう(笑

Ctrl+z` がscreenのエスケープでjk`` はvim。これだけでかなりLinuxと同じ感覚でタスクが選べるようになります。

MigemizeExplorer

こりゃ定番。説明不要ですよねえ。超便利。

craftlaunch

これがないと始まらない。コマンド型ランチャー。craftlanuchラブ。こいつはデスクトップ用と持ち運び用(USBメモリに入れる用)の2個も用意してます。起動用ホットキーはeclipseなんてもんは使ってないので Ctrl+Space です。

俺の場合はほぼ全ての作業の起点がこのソフト。ランチャーとしてのソフト起動から簡易シェルとしてまで大活躍。中でもオススメなのはexplorer.exe(windows標準のシェル)+craftlaunchの連携。

craftlaunchというと「あふ」との連携が有名ですが、俺はあえてexplorer.exeと連携してます。というのも、なにぶん普段使いのOSですから、マルチメディアのファイルなんかも多いわけです。重くてもプレビューが見れたりするのは便利なもんです。日本語のファイル名だし、ファイラーつかってもファイル選択するのがめんどくさいもんです。

どうやって連携してるかというと、基本的に小物アプリ+ショートカットキー。この使い方をはじめるきっかけになったのは「せっかくcraftlaunchからキーボードだけでフォルダ開けるんだから、ホームポジションで楽にキーボードだけで閉じたいなあ」という思い。

ctrl+space,ctrl+[

の2ステップでウインドウが閉じられます。ctrlは押しっぱなしでいいので非常に軽快に閉じられます。鉄の小指を持つemacs使いの人ならなおのことでしょう(笑

その他の連携

フォルダの新規作成

windowのexplorerの不満はフォルダを作るのがめんどくさいことですよね。キーボードならAlt+F W F でしょうか。というわけでfiniのような自作コマンドで対応してます。超テキトーなのですが、あげておきます。

amkdir.zip

こいつを ctrl+nにショートカットとして割り当ててあります。すると・・・ craftlaunchでフォルダを開く→MigemizeExplorerで快適にフォルダをたどる→「フォルダつくりてえ」→ctrl+spaceフォルダ名入力ctrl+nという感じになるわけで、結構ハッピーです。

コンソール

おなじような感じで、表示されているフォルダをカレントディレクトリとしてcmd.exeを起動するものもつくってあります。ほとんどつかわないけど。


以上のような、変なWindowsで日々暮らしています。cltcでブラウザやvim、コンソールを行き来しながらIDEはあんまり使わないでガリガリ書いています。 まぁ、だいたいvmware上のLinuxにいるんですけど(笑 まとめると

  • cltcでctrl+zctrl+j,k 。快適ですよ。
  • MigemizeExplorerはWindows標準装備になればいいのに。
  • craftlaunchはあふと連携してもいいけど、explorerと連携してもハッピーですよ。

という感じです。


エミュレーターのほうはあのあとCPUを若干チューニングして、1フレーム0.1はキリました。今はPPUを書いてるんですが、そろそろ就職に備えて家を探さないといけません。京都と関東を行き来するのはいろいろこたえます。移動中はシグマリオンのPocketSchemeでSchemeでも書いて暇つぶしです。