bash上のエミュレーターi8080

今日、彼らはxonixを作成し、明日はフレームワークとDBMSを備えた別のオペレーティングシステムをタワーに作成します。



最後に、明日が到着しました。 bash(いくつかのdopilivaniyaの後)では、たとえばCP / Mなどの本格的なOSを実行できます また、CP / Mには、DBMS、コンパイラなどが間違いなくあります。







なぜ不要なのか、なぜbashでエミュレータを作成する必要があるのか​​、bashで動作するエミュレータi8080、bashスクリプトの作業を高速化するためのヒント-



bashでエミュレーターを作成する必要がない理由



Bashはゆっくりと動作します。 i8080のような単純なプロセッサであっても、エミュレーション速度が実際の速度の少なくとも1%になることはほとんどありません。 2.2 GHzの周波数のCeleronでは、エミュレーターは毎秒約100の動作速度で動作しますが、2.5 MHzの実際のi8080プロセッサーは毎秒60万回の動作を処理します。



もう1つの重要な問題:bashでは、バイナリデータを操作することはできません。 ポートに出力する場合、またはコード0x01の文字をファイルから読み取る場合、bashは明らかに必要な言語ではありません。



3番目の問題。 エミュレーターの開発は、1〜2時間のタスクではありません。 構文を強調表示するエディターやデバッガーなしでエミュレーターを作成しないでください。 エミュレータを「作成」し始めたとき、私は考えました。 なんてナンセンスだ!」 51番目のオペレーションコードに到達すると、コマンド!=オペレーションコードであり、さらに200のコードを実装する必要があることに最終的に気付きました。 オペレーションコードが200であることをすぐに考慮した場合、エミュレータは作成しません。 そして、書き始めてから、終わらなければなりませんでした。



Bashエミュレーターを使用する理由



その後、それは超大型メガクールです。 そして、それは巨大なbashプログラミング体験を提供します。 その後、エミュレータ内のプログラムが非常にゆっくり実行され、フラグとレジスタの変更を追跡できるようになります。



bashコードを高速化するためのヒント



エミュレーターのコード実行速度は重要です。 bashスクリプトをできるだけ速く実行したい場合は、次のようにします。



ループ内でexprまたはbcを呼び出すと、プログラムが数回遅くなる可能性があります。

$ time ( for ((i = 0; i < 100000; ++i)); do echo `expr 1 + 2` ; done ) real 0m17.000s user 0m13.261s sys 0m8.061s $ time ( for ((i = 0; i < 100000; ++i)); do echo "$(( 1 + 2 ))" ; done ) real 0m3.980s user 0m2.371s sys 0m0.237s
      
      







readarrayコマンドを使用してファイルを配列に読み込むと、ループ内の読み込みコマンドに比べて(ファイルの長さに応じて)大きなゲインが得られることがあり、確かにきれいに見えます。

 $ time ( for ((i = 0; i < 10; ++i)); do while read line ; do rom[${tmpcnt}]=$line ; (( ++tmpcnt )) ; done < bas.e80 ; done ) real 0m6.888s user 0m5.516s sys 0m0.336s $ time ( for ((i = 0; i < 10; ++i)); do readarray -t rom < bas.e80 ; done ) real 0m0.146s user 0m0.048s sys 0m0.004s
      
      







incrementコマンドは、additionコマンドよりも高速です。

 $ time ( for ((i = 0; i < 100000; ++i)); do a=$(( a + 1 )) ; done ) real 0m4.489s user 0m3.692s sys 0m0.108s $ time ( for ((i = 0; i < 100000; ++i)); do (( ++a )) ; done ) real 0m4.053s user 0m3.296s sys 0m0.140s
      
      







16進数システムの数値を10進数に変換するために、次の関数を使用しました。

 hex2dec () { uw=`expr index "0123456789ABCDEF" "${1:0:1}"` lw=`expr index "0123456789ABCDEF" "${1:1:1}"` res=$(( ( ${uw} - 1 ) * 16 + ${lw} - 1 )) }
      
      





exprについて私が言ったことを考えると、あなたは推測することができます:この関数は非常に速く動作しませんでした。 良いmkotは、私が数字をある数字体系から別の数字体系に変換する簡単な方法を提案しました:

 hex2dec () { define -i res res="16#$1" }
      
      





この1回の交換のおかげで、エミュレーション速度は3倍になりました。 したがって、 高度なBashスクリプトガイドを注意深く読んで、ブレーキバイクを発明しないでください。



最後のヒント。 米ドルはフリーシェルに悪影響を与えるため、可能な限り$記号を使用しないようにしてください。

 $ time ( for ((i = 0; i < 100000; ++i)); do a=$(( $a + 1 )) ; done ) real 0m5.155s user 0m4.828s sys 0m0.088s $ time ( for ((i = 0; i < 100000; ++i)); do a=$(( a + 1 )) ; done ) real 0m4.489s user 0m3.692s sys 0m0.108s
      
      







エミュレーターi8080



エミュレーターの開発には約8時間かかりました。 おそらくバグがなかったわけではありませんが(特に論理関数が心配です)、全体的にはうまく機能し、非常に成功しています。 エミュレータに最適化のヒントをいくつか適用しましたが、追加の編集がエミュレータ内のプログラムの実行をわずかにスピードアップすることを期待して、適用しませんでした。 残念ながら、エミュレーターはポートと割り込みの処理をサポートしていませんが、 Radio86のモニタープログラムから「画面に文字を表示する」機能があります。



残念ながら、今日(2017年6月1日)のエミュレータのソースコードは失われます。



次のように実行します。

 $ ./emu.sh program.e80
      
      







レジスタとフラグの内容が表示されます。



プログラムは、1行に1バイトの16進数で記述する必要があります。

空のループを256回実行するプログラムの例:

 3D C2 00 00 76
      
      







マシンコードでのプログラミングのファンは、仮想コンピュータ博物館からの簡単なガイドによってきっと助けられるでしょう。



そうそう、CP / Mについて もちろん、実行できます。 ただし、OSを読み込んで画面に招待状を印刷するには、数分かかる場合があります。



今日は以上です。 みんなハッピーハッキング。



All Articles