独自のプラットフォーム。 パート0.2理論。 通訳CHIP8

はじめに



こんにちは世界! 今日言語仕様 CHIP8の翻訳があります。 この記事には、理論的な部分のみが含まれています。







* COSMAC ELFのすべての栄光*

コスマックELF







CHIP8とは何ですか?



CHIP8は、 RCA COSMAC VIPで使用するために70年代にJoseph Weisbeckerによって開発されたインタープリタ型プログラミング言語です。 その後、 COSMAC ELFTelmac 1800 、ETI 660、DREAM 6800で使用されました。31 (35?)命令により、64 x 32ピクセルの解像度でシンプルなサウンド、モノクログラフィックスを出力でき、16個のユーザーボタンも使用できました。 今日、CHIP-8はエミュレーションの基本的なスキルを教えるために使用されます(解釈ではありません)。 しばしば誤って「エミュレータ」と呼ばれるCHIP-8インタープリターは、増え続けるプラットフォームのプラットフォームに存在します。 この豊富なインタープリターは、CHIP-8インタープリターとシステムエミュレーターの設計の類似性に関連しています。 エミュレーターを理解したい人は、多くの場合、CHIP-8インタープリターを作成することから始めます。









その単純さのために、多数のゲームとプログラムがCHIP-8で作成されました。 これは、プログラマーが多くの場合プログラミング言語に限定されないことを証明しています。







CHIP-8命令はメモリに直接保存されました。 最新のコンピューターでは、バイナリデータをメモリに手動で入力することなく保存できます。 COSMAC VIP仕様では、コードが512バイト(0x200)のオフセットでメモリにロードされると想定しています。 CHIP-8のほとんどのゲームとプログラムは、メモリを操作するとき、そのようなオフセットを想定しています。







CHB-8メモリ内のプログラムは、MSBファースト(最も重要なバイトが最初-最も「重要な」バイトが最初に保存される)を想定して、ビッグエンディアンに保存されることに注意してください。 他の命令がなかった場合、命令は2バイト順に実行されます。







CHIP-8命令にはメモリ内のデータまたは命令へのポインタが含まれているため、コードを変更するには命令内のアドレスを変更する必要があります。 幸いなことに、疑似アセンブラはこの問題を解決します。 CHIP-8の大量のドキュメントには、いくつかの指示(8XY3、8XY6、8XY7、および8XYE)の説明は含まれていませんが、ここでは説明します。







建築



GPR汎用レジスター(RON-汎用レジスター)



すべての算術演算はレジスターを使用します。 CHIP-8は16個のレジスタを記述します。 すべてのレジスタは、8ビットの符号なしで、汎用レジスタを引数として受け入れる命令で使用できますが、最後のレジスタ(V [0xF])(オーバーフローレジスタ)を変更できる命令があることに注意してください。







擬似コード:







u8 V[16] <= 0;
      
      





間違いを犯さないでください。最後のレジスタは、一部の命令で特殊レジスタとして使用されていますが、完全な8ビットレジスタです。 仕様では、操作で最後のレジスタを使用しないことを推奨しています。







I(登録)



レジスターIは16ビットのレジスターです。 それにもかかわらず、最初の12ビットのみを使用します。







擬似コード:







 u16 I <= 0;
      
      





指定漏れ:オーバーフローが発生するとどうなりますか?







PC(登録)



PCレジスタはレジスタIに似ており、指示のみを示します。

指定漏れ:オーバーフローが発生するとどうなりますか?







スタック



CHIP-8は、深さが12セルのスタックを表します。 スタックへの直接アクセス(PUSH / POP /など)はありませんが、スタックを使用する呼び出し命令と戻り命令があります。

注:16個のセルが示されています。 そしてここ -12。







説明書



すべての命令は16進表記です。

指定については、表を参照してください。









レジスタと算術



6XNN-レジスタに定数をロードします。

レジスタの最も単純な命令は6XNN



(16進表記)です。 Xはレジスタであり、NNはレジスタにロードされる定数です。 たとえば、6ABB-値10(V [0xA]、0〜15のレジスタ16)でレジスタに値BB



(187)をロードします。







擬似コード:







 V[X] <= 0xNN
      
      





7XNN-レジスターに定数を追加(ADDI)

定数NNを番号Xのレジスタに追加し、番号Xのレジスタに保存します。オーバーフローレジスタは変更されません。







 V[X] <= V[X] + NN
      
      





8XY0-レジスタを別のレジスタに保存(MOV)

レジスタを操作する別の命令。 8XY0



レコードが8XY0



ます。 Xは、レジスタが番号Yでコピーされるレジスタ番号です。







擬似コード:







 V[X] <= V[Y]
      
      





8XY4-2つのレジスターを追加(ADD)

数値Yのレジスタの値をレジスタXに加算し、値をレジスタXに保存します。オーバーフローが発生した場合、オーバーフローレジスタは1に設定されます。オーバーフローが発生しなかった場合、オーバーフローレジスタは0にリセットされます。







 V[X] <= (V[X] + V[Y]) & 0xFF; V[F] <= (V[X] + V[Y] >= 256);
      
      





私のミスをしないでください:オーバーフローレジスタはいずれの場合でも変更されます。

指定漏れ:レジスタXがオーバーフローレジスタである場合はどうなりますか?







8XY5-レジスターから減算(SUB)

番号XのレジスタからレジスタYの値を減算し、借用が発生した場合(おおよその転送)、オーバーフローレジスタを1に設定します。借用が発生していない場合は、オーバーフローレジスタを0に設定します。







8XY7-逆減算(SUB)

レジスタXをレジスタYからレジスタXの値を減算した結果に設定します。借用が発生した場合は、オーバーフローレジスタを1に設定します。借用が発生しなかった場合は、オーバーフローレジスタを0に設定します。







8XY2、8XY1および8XY3-論理演算(AND、OR、XOR)

レジスタXを演算結果に設定

8XY2-論理的な「および」、

8XY1-論理「OR」、

8XY3-排他的OR

2つのオペランド:レジスタXとレジスタY。オーバーフローレジスタを変更しません。

私の間違いをしないでください:これらの操作はオーバーフローレジスタを変更しません。

注:入力ミスはありません。 8XY2-AND。 8XY1 OR。 8XY3 XOR。







8XY6-右シフト

レジスタYを右にシフトした結果をレジスタXに保存します。

オーバーフローレジスタをレジスタYの下位ビットに設定します。

間違いをしないでください:レジスタYをシフトした結果は、レジスタYではなく、レジスタXに保存されます。







8XYE-右シフト

レジスタYの上位ビットをオーバーフローレジスタに保存します。

レジスタYをレジスタXにシフトした結果を保存します。







CXNN- ランダム 乱数

レジスタXの値を論理「AND」定数NNおよび ランダム 乱数。







実行制御(注翻訳「フロー制御」)



1NNN-NNNへジャンプ

PCをNNN値に入れます。

次の命令はNNNアドレスから実行されます







BNNN-NNN + V0へジャンプ

PCをNNN + V0に配置します。

次の命令は、アドレスNNN + V0から実行されます







2NNN-関数を呼び出す(呼び出しサブルーチン)

2NNNで関数を呼び出します。 値PC + 2がスタックに書き込まれます。







00EE-サブルーチンからの戻り

PCレジスタは、スタックの最後の要素に設定されます。







3XNN-定数とケースが等しい場合、命令をスキップします。

定数NNとレジスタXが等しい場合、命令(PC + 4)をスキップします。 それ以外の場合は、スキップしないでください(PC + 2)。







5XY0-両方のレジスタが等しい場合、命令をスキップします。

レジスタYとレジスタXが等しい場合、命令(PC + 4)をスキップします。 それ以外の場合は、スキップしないでください(PC + 2)。







4XNN-定数とケースが等しくない場合、ステートメントをスキップします。

定数NNとレジスタXが等しくない場合、命令(PC + 4)をスキップします。 それ以外の場合は、スキップしないでください(PC + 2)。







9XY0-レジスタが等しくない場合、命令をスキップします。

レジスタYとケースXが等しくない場合、命令(PC + 4)をスキップします。 それ以外の場合は、スキップしないでください(PC + 2)。







タイマー



CHIP-8には2つのタイマーがあります。 1つのタイマーは遅延をカウントし(翻訳遅延タイマー)、もう1つの「サウンドタイマー」(翻訳サウンドタイマー)は、タイマーの値が0より大きい間、サウンドを再生します。 両方のタイマーは、周波数60Hz(1秒あたり60回)で固有値を減らします。 遅延タイマーから読み取ることができますが、「サウンドタイマー」から読み取ることはできません。







FX15-遅延タイマー値をレジスタXに設定します。

FX07-レジスタXの値を遅延タイマーの値に設定します。

ここではすべてが明確です:)

FX18-サウンドタイマーの値をレジスタXの値に設定します。

注:COSMAC VIPでは、値1は効果がないことが示されていることを思い出してください。







入力(キーパッド)



入力には、0〜9の16個のボタンとAFが使用されます。 仕様の省略:この番号にボタンがない場合はどうなりますか。 例:17。

FX0A-プレス待ち。







レジスタXで指定されたキーが押されるまで実行を一時停止します。

間違いを犯さないでください。キーストロークではなく、この特定のキーのキーストロークのみです。







EX9E-レジスターXの値に対応するボタンが押された場合、以下の指示をスキップします。

EXA1-レジスタXの値に対応するボタンが押されていない場合、以下の指示をスキップします。







ここではすべてが明確だと思います。







登録I



ANNN-登録IにNNNを書き込みます。







FX1E-レジスターXの値をレジスターIに追加します。

オーバーフローが発生した場合、オーバーフローレジスタは1に設定され、それ以外の場合は0に設定されます。







グラフィックとスプライト



注:グラフィックについては、実際の部分で詳しく説明します。

DXYN-スプライトを描画します。







画面上の位置にサイズNバイト(非ゼロ値)のスプライトを描画します:(Vx、Vy)。 スプライトはメモリのアドレスIにあります。スプライトは論理排他的OR(XOR)として描画されます。 ピクセルを再描画する場合(1,1-> 0)、オーバーフローレジスタは1に設定され、そうでない場合は0に設定されます。







仕様省略:









00E0-画面をクリアします。







FX29-レジスタXで指定された番号のスプライトアドレスにIの値を設定します。

スプライトは最初の512バイトに保存されます。







フォント







Cのこのテーブル:







 unsigned char chip8_fontset[80] = { 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0 0x20, 0x60, 0x20, 0x20, 0x70, // 1 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3 0x90, 0x90, 0xF0, 0x10, 0x10, // 4 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6 0xF0, 0x10, 0x20, 0x40, 0x40, // 7 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9 0xF0, 0x90, 0xF0, 0x90, 0x90, // A 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B 0xF0, 0x80, 0x80, 0x80, 0xF0, // C 0xE0, 0x90, 0x90, 0x90, 0xE0, // D 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E 0xF0, 0x80, 0xF0, 0x80, 0x80 // F };
      
      





ここから撮影。







FX33-レジスタ値をI、I + 1およびI + 2の2進10進形式で保存します。

参照: バイナリ10進コード (およそBCD-バイナリコード10進)







レジスタとメモリ



FX55-レジスタV0〜VXの値をメモリ開始アドレスIに包括的に保存します。

実行後、レジスタIはI + X + 1に等しくなります。一部のインタープリターはこの規則を無視しますが







FX65-レジスタV0〜VXを、アドレスIから始まるメモリに格納されている値に包括的にロードします。

実行後、レジスタIはI + X + 1に等しくなります。一部のインタープリターはこの規則を無視しますが







残りすべて



通訳はどの周波数で動作しますか?







これについては、オリジナルには何も見つかりません。 インターネットからさまざまな周波数が得られました: 1000Hz840Hz540Hz 、500Hz、さらには60Hz。







ジャンプが揃っていない場合はどうなりますか?

これに関する情報は見つかりませんでしたが、命令はダウンロードされて実行されると思います。







最初の512バイトから読み取りまたは書き込みを行うとどうなりますか?

再び何も見つかりません。 録音時には0を指定して無視する必要があると思います。







終わり



これで終わりです。 タイプミスについては、プライベートメッセージを書きます。 どんなコメントでも喜んでいます。 実用的な部分が作成されています。 実際的な部分は、C(C ++ではない)およびSDL2になります。







ここでオリジナルを見つけることができます。 ここにもう少し情報がありますここで別の実用的なチュートリアル。








All Articles