Mov命令の実装
AnalyzeBinaryメソッドで御膳立てされていますので、Mov命令の実装はとても簡単です。各レジスタに指定された値を設定するだけです。
'Mov命令の実装 Private Sub Mov(ByVal cmd As OpeCode) Select Case cmd.Destination Case RegisterName.EAX Me.EAX = cmd.Value.ValueU32 Case RegisterName.EBX Me.EBX = cmd.Value.ValueU32 Case RegisterName.ECX Me.ECX = cmd.Value.ValueU32 Case RegisterName.EDX Me.EDX = cmd.Value.ValueU32 Case RegisterName.AX Me.AX = cmd.Value.ValueU16 Case RegisterName.BX Me.BX = cmd.Value.ValueU16 Case RegisterName.CX Me.CX = cmd.Value.ValueU16 Case RegisterName.DX Me.DX = cmd.Value.ValueU16 Case RegisterName.AH Me.AH = cmd.Value.ValueHighByte Case RegisterName.AL Me.AL = cmd.Value.ValueLowByte Case RegisterName.BH Me.BH = cmd.Value.ValueHighByte Case RegisterName.BL Me.BL = cmd.Value.ValueLowByte Case RegisterName.CH Me.CH = cmd.Value.ValueHighByte Case RegisterName.CL Me.CL = cmd.Value.ValueLowByte Case RegisterName.DH Me.DH = cmd.Value.ValueHighByte Case RegisterName.DL Me.DL = cmd.Value.ValueLowByte End Select End Sub
このプログラムを見たら分かると思いますが、レジスタのビット数にさえ注意を払えばとても簡単です。Mov命令の様な単純な機械語はそこへ辿りつくまで大変ですが、辿りつけばとても簡単なのです。
後はテストドライバがこの機械語を使用するように改良するだけです。
テストドライバの変更
Mov命令の実装が済みましたので、後はテストドライバでそれを使うようにするだけです。次のプログラムを追加してください。
'Mov命令を実行する Private Sub MoveDataButton_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MoveDataButton.Click 'レジスタとコピーする値を決定 Dim binary(1) As Byte Dim name As RegisterName = RegisterCombo.SelectedIndex binary(0) = IntelCpu.GetBinary(CommandName.Mov, _ RegisterCombo.SelectedIndex) 'レジスタのビット数に応じてコピーする値を用意する If name < RegisterName.AH Then ReDim Preserve binary(4) Dim value As UInteger 'エラーチェック If name < RegisterName.AX Then If UInteger.TryParse(RegisterText.Text, value) = False Then MessageBox.Show("0~" & UInteger.MaxValue.ToString() _ & "までの数値を入力してください。", _ "入力エラー", _ MessageBoxButtons.OK, _ MessageBoxIcon.Error) RegisterText.Focus() Exit Sub End If Else If UShort.TryParse(RegisterText.Text, value) = False Then MessageBox.Show("0~" & UShort.MaxValue.ToString() & _ "までの数値を入力してください。", _ "入力エラー", _ MessageBoxButtons.OK, _ MessageBoxIcon.Error) RegisterText.Focus() Exit Sub End If End If '値を分解して保存 Dim values As Byte() = IntelCpu.DivisionValue(value) values = IntelCpu.GetLittleEndianValue(values) For i As Integer = 0 To 3 binary(i + 1) = values(i) Next Else '1バイト(8ビット)レジスタの場合 Dim value As Byte 'エラーチェック If Byte.TryParse(RegisterText.Text, value) = True Then binary(1) = value Else MessageBox.Show("0~" & Byte.MaxValue.ToString() & _ "までの数値を入力してください。", _ "入力エラー", _ MessageBoxButtons.OK, _ MessageBoxIcon.Error) RegisterText.Focus() Exit Sub End If End If '用意したバイナリを送ってMov命令を実行する Me.cpu.ReadBinary(binary) Me.cpu.AnalyzeBinary() Me.cpu.ExecuteCommand() End Sub
初心者の方はプログラムの行数に圧倒されてしまったかもしれませんが、簡単な処理の集まりで、大まかに分けると3つだけです。これから丁寧に解説しますので安心して読み進めてください。
このプログラムのポイントはバイナリを用意してIntelCpuオブジェクトへ渡すという点です。今までの記事を思い出してください。CPUは0と1のバイナリしか理解しないので、すべての情報をバイナリに変換する必要があります。このクリックイベントではそれを行っているだけです。上から順に解説します。
1つ目の処理ではMov命令であることと、対象となるレジスタを指定するバイナリを決定しています。やっていることは単純そのもので、画面で指定したレジスタを判別してから、前回実装したIntelCpu.GetBinaryを実行して対応するバイナリを取得しているだけです。
2つ目の処理ではコピーする値を決定しています。この処理はレジスタのビット数によって異なります。なぜならば1バイト(8ビット)のレジスタの場合、特に値を加工する必要がないからです。こちらの方は説明の必要がないと思いますので、もう一つのコードブロック(IF文のTrueコードブロック)について説明します。
If name < RegisterName.AH Then 'Trueコードブロック Else 'Falseコードブロック
Trueブロックでは、まず初めに値のエラーチェックをしています。1ワード(16ビット)レジスタの場合はUShort型、ダブルワード(32ビット)レジスタの場合はUInteger型として正しい値が入力されているかチェックしています。このチェックが正しければ次へ処理を進めています。次はコピーする値を分解しています。なぜこのようなプログラムが必要なのかと言うと、バイナリをバイト配列としてIntelCpuオブジェクトに渡すからです。詳しい説明は前回書いていますので参照してください。
3つ目の処理では、用意したバイナリを送ってMov命令を実行しているだけです。つまり、CPUの基礎動作である、命令読み込み、命令解析、命令実行を順番に指定しているだけなのです。
これでドライバの準備は完了です。実行してみてください。対象となるレジスタに任意の値を設定できるはずです。
まとめ
いかがでしたでしょうか? 今回の記事を読めば、機械語の命令を実装することは意外と難しくないことが分かっていただけると思います。
これは何も機械語の実装の話だけではありません。物事はなんでもそうです。プログラミングは実のところ、大半は対象を分析するまでが難しいのです。IT業界の人は仕様が大事だとよく聞くと思います。それはこのことを指しています。実装は勿論大事ですが、設計をうまくすることにより成否の大部分が決まってしまうのです。
この記事を通じて、初心者の方もプログラミングを難しいと身構える必要がないことが伝われば幸いです。一人でも多くの人が、プログラミングを楽しいと感じ、バイナリプログラミングにチャレンジしてくれるよう筆者は願っています。
次回は簡単な四則演算に関する機械語を実装します。お楽しみに。
