honeylab's blog

各種ハードウェアの改造、主にファミコンミニなどをやってます(ました)

NES Classic MiniのLinuxをcloverconで操作してslを走らせる

NES Classic Miniではコントローラがi2cで接続され、
Linux上からは/dev/event や /dev/input/event で取得することができます。
しかし、それを触るにはプログラムを書かなければいけないため少々面倒です。
将来的に、直接キーボードを接続する前準備として、
コントローラ端子にキーボードをつなげるようにドライバを改変してみました。
もちろん、将来接続するのはアレ↓ですがw

f:id:honeylab:20170210134741p:plain

 

さて、とりあえずコントローラのボタンとキーの割り当ては下のようにします。

↑ "o"

← " r"

↓ ”e”

→ "t"

SELECT "b"
START "ENTER"

B "l"
A "s"

 

こうすると、起動後の"login:"に 対して "root [ENTER]"を押してログインでき、
"ls [ENTER]"でファイル一覧が取得できます。


clovercon.cを少し改変

f:id:honeylab:20170210134343p:plain

f:id:honeylab:20170210134539p:plain

 

 

ところで、おっさん達はその昔端末に"sl"というプログラムが入っていることがあったのを覚えているかと思います。

https://ja.wikipedia.org/wiki/Sl_(UNIX)

Unix系OSにおいて、ls は最もよく使われるコマンドであるが、lsコマンドを実行しようとしてslとミスタイプすることがしばしばある。そのような場合、コンピュータは「sl」という存在しないコマンドを求めてシステムを全検索してしまい、70年代から80年代当時の処理能力の遅いコンピュータではそれにしばらく時間がかかり、作業が中断してしまうことがあった。そこでそれを防ぐため、「sl」と言う名のダミーのプログラムを用意することがあった。

このslも、そういったダミープログラムの一つであるといえるが、ミスタイプによってロスする時間(現代においては殆ど一瞬である)よりも、SLが走り抜けるのを待っている時間のほうが長いなど、ジョークプログラムとしての性格が強い。

Ctrl+Cでも停止できず、数分間も延々とSLが走っている姿を見させられるため、嫌がらせに近いと評価する者もいるが、学生時代の豊田准教授は本ソフトのマニュアルにおいて「高度に発展した、キータイプ矯正を目的とするアニメーションプログラムである」と主張している。

そんなslが、buildrootのパッケージに入っていたのでついでに入れてみました。

本当は[B][A][START] でlsしなければいけない時に、slしてしまうとどうなるか。
以下の動画でどうぞ。

 

ファミコンミニでスーファミエミュレータsnes9xを動かす

さて、2ボタンしかない日本のファミコンミニSNES入れてどうすんだといわれそうですが、
まぁ海外モデルでは複数ボタンもあるしどうにかなるんじゃね、ということで試していたSNESエミュレータがぼちぼち動きそうなので少しまとめておきます。

 

とりあえず、retroPiとかにも持っていかれる元のsnes9xを選定してみました。

GitHub - domaemon/snes9x-sdl: Snes9x - Portable Super Nintendo Entertainment System (TM) emulator

 

ここからcloneしてコンパイルします。
まず、ファミコンミニに非常に近いA33上で動かしてみることにします。

このA33にはLCDをつけていて、X11とかはちゃんと動いていますが、
適当にコンパイルした状態だと色がきちんと出ないうえに、
横に二つ並んで表示される、という困った状態になりました。

 

何となく推測すると、フレームバッファの色解像度と
出力されているLCDの解像度が合わない、ということのようです。
ここで早めに「きれいに2つ並んでるんだから、元が16bitで32bitディスプレイなんだな」と気づけばよかったんですが、そこに気付くまでには結構時間がかかりましたw

これは、結構早い段階でファミコンミニでも再現できていたため、
A33上で同じ現象が出る、ということはファミコンミニでも直すのに役立ちました。

↓のはpcDuinoでコンパイルした奴をファミコンミニに持って行ったものです。
結構前から動かせそうで動かせてなかったんですよね。

 

で、いろいろ調べてみたところ、ファミコンミニフレームバッファHDMI出力は
「1280x720 32bit」にすればきれいに出る、ということがわかりました。

ここで、snes9xのSDLポートはどうなっているかというと、

f:id:honeylab:20170206192342p:plain

見事に16bit固定のようです。さらに、

f:id:honeylab:20170206192426p:plain

のように、内部レンダリングも16bit固定になっていました。
もしかして、ここを変えればいいんじゃね?と思いましたが

f:id:honeylab:20170206192856p:plain

ここに指定できるのは、結局16bitカラーのみのようです。
エミュレーションの都合上仕方がないようなので、作成されたバッファを32bitに転送することで色変換を実現しました。

 

内部バッファと一緒にスクリーンは別途作って

f:id:honeylab:20170206193400p:plain

f:id:honeylab:20170206193510p:plain

フリップ時にいったん経由して描画する

そんな感じなのと、SDL1.2に依存しているので拡大縮小が出来ず、最大パフォーマンスが出ていませんが、SDL2に移行できればSDL_BlitScaledが使えて、
そうすると内部バッファとの関係でもう少しパフォーマンスが上がるかもしれません。

 

で、今のところはとりあえずこんなもんです。

上から下に移動してる青線はフレーム描画のテスト用に書いてるものです。 


ちょっとまだ遅いし、画面解像度の1280x800を使い切れていない(小さめで書いてる)ので、ぼちぼち調整して、あとはパッド対応をしたらどうにかなるかな。

 

fcuexをファミコンミニ向けにコンパイルする(not yet)

同様に、fcuexもA33向けにまずコンパイルしてみた。

 なんかすごいもっさりなんだけど…大丈夫かこれ?

同じように、SDLの依存がひどいので、再コンパイル待ち
コンパイルできたらファミコンミニに持っていこう。

snex9x-sdlをファミコンミニ向けにコンパイルする(not yet)

とりあえず、snes9x-sdlコンパイルしてA33で動かしてみた。

SDLはA33上でapt-get した。

ひろみつ(85.1kg) on Twitter: "snes9x-sdl on A33 board https://t.co/KE8KKGgTFL"

 

なんかもっさりしてる?
こないだ一回ファミコンミニで動かしたときはそんなんでも無かった気がするんだけどなぁ

 

で、ファミコンミニに持っていこうとするが、依存ライブラリが多すぎてダメだこりゃw

と言うわけで、改めてSDLを最小限構成で自前ビルドしてる所なう。

root@A33-OLinuXino:/home/olimex/SDL-1.2.15# ./configure --without-x --disable-directfb --disable-pulseaudio --disable-pulseaudio-shared --disable-arts --disable-nas --disable-diskaudio --disable-dummyaudio --disable-video-x11 --disable-input-tslib

で、できたSDLの依存先は

root@A33-OLinuXino:/home/olimex/SDL-1.2.15# ldd /usr/local/lib/libSDL-1.2.so.0
libm.so.6 => /lib/arm-linux-gnueabihf/libm.so.6 (0xb6eb0000)
libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0xb6e9c000)
libdirectfb-1.2.so.9 => /usr/lib/arm-linux-gnueabihf/libdirectfb-1.2.so.9 (0xb6e3b000)
libfusion-1.2.so.9 => /usr/lib/arm-linux-gnueabihf/libfusion-1.2.so.9 (0xb6e25000)
libdirect-1.2.so.9 => /usr/lib/arm-linux-gnueabihf/libdirect-1.2.so.9 (0xb6e05000)
libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6de2000)
libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6cf1000)
/lib/ld-linux-armhf.so.3 (0xb6f99000)

うーん、なんか思って無いのが入ってるぞ?--disable-directfbしたはずなのになんで入っちゃってるんだろう…
でもまぁこのぐらいなら持っていける?とか思ったりもする

 

さて、改めてコンパイル中…

allwinner A33ボードを買いました

ロスコンパイラが嫌いなため、どうにかセルフコンパイル環境を作ってやろうと
ファミコンミニのR16と実質同じはずのA33のボードを買いました。

A33-OLinuXino - Open Source Hardware Board

 

最初、国外から通販で買えることに気付かず、すごい悩んでいたのですが、
発送先を指定して、paypalで送金したら数日で届きました。すごいな。

 

 ファミコンミニ用にコンパイルしたu-bootから起動してみます。
MMCもちゃんと認識します。
ファミコンミニがMMCから起動しないのはソフトのせいじゃないのか…?

 

とりあえず、オフィシャルのカーネルdebianを書いて簡単に動作確認をしてみました。カーネルのバージョンは、3.4.39+とのことです。

 

さて、試しにNESから借りてきたkachikachiを動かしてみます。

 当然、コマンドラインオプションとかは普通に表示されますが、
NESを指定して画像描画しようとするとCould not initialize EGLで終了してしまいます。
これは、pcDuino A10で動かしたときも同じでした。
どうも、Maliのドライバが正しく読み込まれていないんじゃないかと思います。

オフィシャルのfsを調べているのですが、やはり、maliのドライバの痕跡が全然ありません。
maliを配ること自体に何か問題があるんでしょうか?

 もともとのNESのイメージには含まれてるんだけど、これ3.4.11用のやつだからたぶん動かないよね?

3.4.11をa33 olimex用に構築する、でもいいと思うんだけど、otgちゃんと動くの?とかいろいろ不安。

 

とりあえずmaliを探しに行こう…

ファミコンミニ テストパッドを改めて確認する

どうにかUSB-HOST使えないかな、っていうのと、
まだ何か使えるピンがあるんじゃないか、と気になっている人がいるようなので
少しまとめてみました。

 

SIDE-A で出てるのはほとんどAXP223の電源確認周りです。

f:id:honeylab:20170204123331p:plain

電源アダプタが付くんじゃないか、と考えられていたところは確かに、L二つを通して
AXP223のACINにつながってますが、Cとかもないので、その辺を調整しないといけなそうですね。

 

SIDE-Bで、他に使えそうなピンはほとんどないですね。
一応、コントローラ用にGPIOが2本と、TWIが2系統あるので、
その辺を工夫するしかないですね。

CPUの右肩にあるのは明らかにRTC用の32KHz振動子用です。
これ以外の詳しいテストパッドは、

http://linux-sunxi.org/Nintendo_NES_Classic_Edition

ここにもありますので参照してください。


AXPやUSB周りの回路図を近々起こしてみようかな、と思ってはいる。

 

f:id:honeylab:20170204123455p:plain

ニンテンドークラシックミニのリセットボタンについて

ニンテンドークラシックミニのリセットボタンは、ファミコンのように直接CPUをリセットするボタンではなく、普通のキーボードやボタンと同じように認識されています。
メニューからROMを選んで、内蔵エミュレータ(kachikachi)を起動した後、
リセットボタンの入力があれば、その瞬間のステートセーブとスナップショットをとって、エミュレータを終了するようになっています。


さて、ソフト的にどうなっているのかを調べてみました。
まず、リセットボタンはタダのデジタルIOではなく、CPUのKEYADC(LRADC)というポートに接続されています。

一つのピンである程度の数の入力を受けられるよう工夫されています。

f:id:honeylab:20170124210737p:plain

 別のマイコンでのことですが、よく使われる手法で以下のページなどが参考になります。

少ないポートでキー入力 - 無作為研究所

以下の回路は、ニンテンドークラシックミニのCPUと良く似た
A33 CPUを採用したOlimexのボードの回路図です。

f:id:honeylab:20170124204656p:plain

お馴染みの「リセットボタンを押すとFELに入る」、と言うのはこの様になっています。
実際には、あと何個かボタンがつけられるはずです。
この端子はlinuxが起動すると sunxi-keyドライバで受け取り、イベントとして取得できるため、エミュレータがハンドルできます。

ソースコードとしては以下のように書かれています。

f:id:honeylab:20170124205513p:plain

ボタンが押されると割り込みがかかり、レジスタから押されたキーを判定します。

f:id:honeylab:20170124205957p:plain

キーマップはこんな感じ。
いわゆるAndroidタブレットなんかに最初からついてるキーが割り当てられています。
さらに、Linuxからイベントを見てみると

f:id:honeylab:20170124210126p:plain

リセットボタンを押して離すと、上記のイベントがとれます。
115と言うのがキーコード、これはKEY_VOLUMEUPです。
つまり、リセットボタンではなくVOLUMEUPボタンだったんですねw

実は、AllwinnerのAndroidタブレットはまさにそのまま、VOLUMEUPがファーム更新のトリガになっています。(そういった取っ掛かりから、今回の解析もスムーズに始まったようです)

どっかに抵抗値の一覧があると思うので、リセットボタンの端子にちょっと外付ボタンを追加すると、別のことができるボタンをつけることもできるかも知れませんね。
あと、このキーをハンドルする用に既存の別のエミュレータを改良すれば、
メニューから呼ばれて、セーブステートを使うようにインストールすることもできるはずです。
(セーブステートや、スナップショットをとるインターフェイスは解析済みです)