キャリー・ボローでセットされるフラグレジスタ自体は64ビットCPUの場合、64ビットの大きさがあります。ここでは算術演算に関わるもののみ紹介しました。今後使用するビットは登場した際に改めて紹介します*4。1か、Wikibooksの記事が分かりやすいです。共に本書末尾の「参考情報」で紹介しています。以上をまとめると、前節の機械語コードにフラグ確認の処理を追加するとリスト3.5のようになります。-1実行結果は前節と変わりませんが、これでポーリングによるシリアル送信をちゃんと実装できました。受信も追加しエコーバックプログラムを作るこの章の最後に、シリアルポートからの受信データの取得を行ってみます。受信した文字をそのままシリアルポートへ送信することで、エコーバック処理*5を実装してみます。入力したキーに対応する文字がそのまま画面へ表示される処理。シリアルドライバの送受信の動作確認としてよく使われます。この節のサンプルディレクトリは「033_echoback」です。受信バッファにデータが来るのを待つ(命令21「jne」/命令22「pause」)まずは、受信バッファにデータが来るのを待ちます。シリアルポートの受信バッファにデータがあるか否かもステータスレジスタLSRで確認できます。受信バッファに1つ以上のデータがあれば、LSRのビット0がセットされます(表3.10)。受信バッファに1つ以上のデータがあるsample.txtに受信バッファに1つ以上のデータが来るまで待つ処理を追加するとリスト3.6の通りです。「シリアルポートのステータス取得」のコードブロックはシリアル送信の際と同じものです。「受信バッファが空であればpauseしステータス取得まで戻る」のコードブロックは、これまでと少し異なります。Equal」の略です。je命令の逆で、「ゼロフラグがセットされていなければジャンプ」という挙動になります。構文もje命令等と同様で表3.11の通りです。fe+rel_addrそして、ALへ格納したステータス値と0x01でANDの結果に対して、以下の振る舞いを実装しています。受信バッファにデータ無いので、pauseして再度ステータス取得ここでは、「ビジーループで待つの際はpause命令を挟む」という事をするためにこのようなロジックにしています。「pause」命令は、「ビジーループしている」事をCPUへヒントとして伝える命令で、ビジーループにこの命令を挟んでおくことでCPUの実行効率を改善する効果があります。(詳しくは後述のコラムにまとめています。)pause命令はオペランドが不要で、構文としては表3.12の通りです。90併せて、送信バッファが空になるのを待つ処理にも、pauseを挟んでおくことにします(リスト3.7)。violation)」を防ぐことができるためです。インテル等のCPUには「投機的実行」と呼ばれる機能があり、現在実行している命令よりも先の命令をCPU内のバッファへ予め読み込み、場合によっては先に実行しておくことで、CPUの性能最適化を図っています。条件付きジャンプ命令等、命令を評価し終えるまでどこへ分岐するか分からない命令があると、その先をどのように先読みするかが問題になります。この時、インテル等のCPUでは「過去にどちらのコードパスを多く通ったか」等の統計値を元に、分岐先を推測して先読みを続行します。今回のようにCPUとしてはほとんどの時間を「フラグ設定待ち」で過ごしていると、命令先読みのバッファは「フラグ設定待ちの処理」の先読みで埋め尽くされ、それらの処理が予め実行される形で最適化が行われます。これは、「次もきっとフラグ待ちだろう」という推測で最適化されている状況です。そのため、いざフラグが設定された時に、推測が外れ、先読みしたバッファの内容や予め実行した処理もムダになり、実行効率が低下します。これを「メモリ順序違反」と呼びます。pause命令があるとCPUがこのような誤った先読みをしなくなり、メモリ順序違反を防ぐことができます。(M-U)」にあるpause命令の解説をご覧ください。(本書末尾の「参考情報」にPDFが公開されているページのURLを載せています。)受信バッファのデータを取得する次に受信バッファのデータを取得します。Register)」です。RBRについてIOアドレス0x03f8レジスタサイズ1バイトRBRのIOアドレスはTHRと同じです。同一のアドレスに対して、in命令による読み出す時は「RBR」へ、out命令による書き込み時は「THR」へ、となるように内部の回路が組まれています。RBRからデータを読み出す処理を追加するとリスト3.8の通りです。・・・in命令の箇所では、受信バッファからALレジスタへ受信データを格納しています。ALレジスタはその他のin/out命令の箇所でも使用するため、ALへ格納したデータはmov命令でBLレジスタへコピーしています。mov命令の新構文(8ビットレジスタから8ビットレジスタへコピー)ここで、8ビットレジスタから8ビットレジスタへ値をコピーするmov命令の構文を紹介します。c0+reg_src_dst「reg_src_dst」については表3.15の通りです。0x3f2章のimul命令で紹介した表とは異なり、各行が「第1オペランド(src)」で、各列が「第2オペランド(dst)」となっている点に注意してください。受信バッファから取得したデータを送信する受信バッファからデータを取得できたので、今度はそれを送信してみます(リスト3.9)。追加・変更(ここまで)特に新たな要素はありません。受信したデータはBLレジスタにあるため、それをALへコピーし、DXレジスタへ送信バッファアドレスを設定の上、out命令でシリアルポートへ送信しています。動作確認これまで通り、ビルドし、動作確認してみてください。入力したキーに対応する文字がシリアルの画面へ表示されます。改行を入力すると、次の行へ移らずに行頭へ戻ってしまいます。"hoge"と入力したが、次の行へ移らない。Return、復帰コード)のみであるためです。Feed)を送信していないため、改行キーを入力した際に、行頭に移動するのみで次の行へ移動しなかったのでした。受信バッファから取得したデータを送信後、受信したデータがCR(0x0d)であった場合、LF(0x0a)を追加で送信するようにします(リスト3.10)。追加・変更(ここまで)新たに「cmp」命令が登場しました。これはオペランドで指定した数値の比較を行う命令です。挙動としては「第2オペランド(dst)を書き換えないsub命令」です。sub命令は第2オペランドから第1オペランド減算した結果を第2オペランドへ格納しますが、cmp命令は減算まで行ってフラグレジスタのみ変化させた後、減算結果は捨てます。構文としては、cmp命令もsub命令同様、レジスタとしてALが対象の場合は1バイト少ない構文があります(表3.16)。値(8bit)ALを含むその他のレジスタについては表3.17の通りです。値(8bit)追加した処理でやっていることとしては、送信処理後、cmp命令を使用して、ALレジスタに残っている送信済みの文字と0x0d(CR)を比較し、等しくなかった場合はjne命令で先頭まで戻り、等しかった場合は、以降のLF送信処理へ進みます。LF送信処理は、BLへ0x0a(LF)を格納し、送信のためのシリアルポートステータス確認処理(*1)までジャンプするだけです。動作確認この状態で動作確認してみると、改行まで反映されているはずです。