ExecuteCommandメソッドの変更点
まずはコードを見てください。
'解析済みの命令を実行します。 Public Sub ExecuteCommand() Dim cmd As OpeCode While cmds.Count <> 0 cmd = cmds.Dequeue() Select Case cmd.Name '命令を選択して実行 Case CommandName.Mov Mov(cmd) End Select End While End Sub
このコードは大変簡単です。あらかじめAnalyzeBinaryメソッドでバイナリを解析し、実行するべき命令をcmdsキューに格納しているので、それを一つ一つ取り出して適切な命令を実行するだけです。
最後にMov命令について説明します。
Mov命令とレジスタの初期値について
「Mov命令」とは、レジスタに任意の即値(132などの定数)をコピーしたり、メモリからレジスタに値をコピーしたりする命令です。この命令は必須です。何故かと言うと、実際のレジスタは初期状態に何の値が入っているかわからないからです。初期値を設定しないでレジスタを使用した時の動作はIntel社が保障していません。
より正確にシミュレートするために、まずはレジスタの初期値を実装します。先述のとおり、レジスタの初期値は何が入っているか分からないので、IntelCpuオブジェクトのコンストラクタで、各レジスタの値をランダムに設定することにします。
'コンストラクタ Sub New() '必要なキューを初期化 binarys = New Queue(Of Byte) cmds = New Queue(Of OpeCode) 'ランダム値生成オブジェクトを準備 Dim mask As ULong = CULng(UInteger.MaxValue) Dim seed As Integer = CInt((DateTime.Now.Ticks And mask) >> 1) Dim rand As Random = New Random(seed) 'レジスタの値をランダムに設定 Me.EAX = rand.Next(0, Integer.MaxValue) Me.EBX = rand.Next(0, Integer.MaxValue) Me.ECX = rand.Next(0, Integer.MaxValue) Me.EDX = rand.Next(0, Integer.MaxValue) End Sub
キューの初期化部分は前回実装したので割愛し、ランダムな値を生成するオブジェクトを準備する部分について説明します。
Randomオブジェクトはランダム値を生成するためのオブジェクトです。しかし、規定コンストラクタの
Dim rand As Random = New Random()
では、ある程度生成される数値にパターンができてしまいます。ですから、
Dim rand As Random = New Random(seed)
とランダム値を生成する基となる値「シード値」を指定する必要があります。もちろんこのシード値は定数では意味がなく、実行のたびに変化する値が必要となります。この場合、現在の時刻を表すDateTime.Now.Ticksプロパティが適任です。
しかし、このプロパティの値はLong型で、Randomのコンストラクタが必要としている型はIntegerなので、そのままではオーバーフロー(限界値を超えている状態)になってしまいます。ですから、上位32ビットを無視するようにビット毎のAND論理和を行い、最後に1ビット算術右シフトすることによりIntegerの範囲内でシードを生成しています。
ここまでくれば後は各レジスタに値を設定するだけです。しかもすべてのレジスタに設定する必要はありません。その理由は、レジスタが入れ子状態だからです。32ビットレジスタの値を設定すれば、16ビットのレジスタと8ビットのレジスタは結果的に値が変わりますので、いちいち設定する必要がないのです。
これでレジスタの初期値にランダム値を設定するプログラムは完成しました。後はテストドライバの開始時にその値を表示するだけです。テストドライバのロードイベントに次のプログラムを追加してください。
Private Sub TestForm_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'レジスタの初期値を表示 Me.ShowEaxRegisters(New Register(cpu.EAX)) Me.ShowEbxRegisters(New Register(cpu.EBX)) Me.ShowEcxRegisters(New Register(cpu.ECX)) Me.ShowEdxRegisters(New Register(cpu.EDX)) End Sub
各レジスタの値がランダム値になっているかチェックするために、テストドライバを実行してください。偶然に0になるレジスタもあるかもしれませんが、各レジスタの値がランダムに設定されている筈です。もし何度実行してもレジスタの値が0と表示される時は、どこかが間違っていますので、もう一度この記事を読みながら自分のプログラムを再度チェックしてください。もしどうしても分からない場合は、サンプルプログラムと自分のプログラムを見比べてください。
ここまできたらすべての準備は完了です。いよいよMov命令の実装ができます。
