各種機械後命令の修正
前項で機械語の実行を終了したことを通知するイベントを実装しましたので、むろん今まで実装した機械語命令も修正せねばなりません。全ての命令に修正を加えているのですが、あまりにも長くなりますので、一例だけサンプルコードから抜粋して説明します。
'DIV命令の実装 Private Sub Div(ByVal ope As OpeCode) Dim before As ULong Dim value1 As ULong Dim after As ULong Dim beforeRemainder As UInteger Dim afterRemainder As UInteger Select Case ope.BitCount Case 8 '値を先に用意 before = Me.AL beforeRemainder = Me.AH Dim value As UShort If ope.IsHi Then value = ope.Value.ValueHighByte Else value = ope.Value.ValueLowByte End If value1 = value '剰余を算出 Dim remainder As UShort = Me.AX Mod value '商を算出 Dim tmp As UShort = Me.AX - remainder Dim quotient As UShort = tmp / value '結果をレジスタに反映する Me.AH = CByte(remainder) Me.AL = CByte(quotient) after = Me.AL afterRemainder = Me.AH Case 32 '値を先に用意 before = Me.EAX beforeRemainder = Me.EDX Dim value As UInteger = ope.Value.ValueU32 value1 = value '剰余を算出 Dim remainder As UInteger = Me.EAX Mod value '商を算出 Dim tmp As UInteger = Me.AX - remainder Dim quotient As UInteger = tmp / value '結果をレジスタに反映する Me.EDX = CByte(remainder) Me.EAX = CByte(quotient) after = Me.EAX afterRemainder = Me.EDX End Select Me.OnDivExecuteCommandEnd(CommandName.Mul, before, value1, after, beforeRemainder, afterRemainder) End Sub
DIV命令実装と実行の項で掲載したコードと見比べてください。ローカル変数が増え、最後にイベントを発行しているのに気づいたと思います。初心者の人は一見すると複雑に見えますが原理は簡単です。イベントを発行するに当たって、必要な情報をローカル変数に保存しているだけです。DIV命令そのものの動きは変わったわけではありません。その点さえ分かれば、他の命令についても理解できると思います。一度各命令の実装を見てください。
これで機械語命令が実行された際の情報を外部に通知できます。後は受け取る側のテストドライバを修正すれば完成です。
テストドライバの修正
テストドライバで新しく実装したイベントを受け取るには、フォームのロードイベントでイベントハンドラを追加します。
Private Sub TestForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'テスト対象となるIntelCpuオブジェクトを用意する cpu = New IntelCpu() AddHandler cpu.RegisterValueChanged, AddressOf RegisterValueChanged AddHandler cpu.FlagValueChanged, AddressOf FlagValueChanged AddHandler cpu.MoveCommandEnd, AddressOf MoveCommandEnd AddHandler cpu.CalculateCommandEnd, AddressOf CalculateCommandEnd 'レジスタの初期値を表示 Me.ShowEaxRegisters(New Register(cpu.EAX)) Me.ShowEbxRegisters(New Register(cpu.EBX)) Me.ShowEcxRegisters(New Register(cpu.ECX)) Me.ShowEdxRegisters(New Register(cpu.EDX)) 'エラーを防止するために、レジスタが必ず選択されている状態にする。 RegisterCombo.SelectedIndex = CInt(RegisterName.EAX) CmdCombo.SelectedIndex = CInt(CommandName.Mov) '値を見やすくするための設定 format = New NumberFormatInfo() format.NumberDecimalDigits = 0 End Sub
後はイベントを処理するためのメソッドを実装します。
'情報欄にMov命令実行内容を表示する Private Sub MoveCommandEnd(ByVal sender As Object, ByVal e As MovCommandEndEventArgs) ResultLabel.Text = "値が" & e.Value.ToString("N", format) & "に初期化されました。" End Sub '情報欄に計算結果を表示する Private Sub CalculateCommandEnd(ByVal sender As Object, ByVal e As CalculateCommandEndEventArgs) ResultLabel.Text = e.BeforeValue.ToString("N", format) & _ " " & e.Sign.ToString() & " " & _ e.Value.ToString("N", format) & " = " & e.AfterValue.ToString("N", format) End Sub
そして、RegisterValueChanged
メソッドを以下のように修正します。
Private Sub RegisterValueChanged(ByVal sender As Object, ByVal e As RegisterValueChangedEventArgs) 'レジスタの値を反映させる Select Case e.Gruop Case RegisterGruop.A Me.ShowEaxRegisters(e.AfterValue) Case RegisterGruop.B Me.ShowEbxRegisters(e.AfterValue) Case RegisterGruop.C Me.ShowEcxRegisters(e.AfterValue) Case RegisterGruop.D Me.ShowEdxRegisters(e.AfterValue) End Select End Sub
前回のサンプルコードと見比べてください。随分と実装が簡単になったのが分かってもらえると思います。
これで全ての実装作業は終わりです。早速実行して色々試してください。
まとめ
いかがでしょうか? DIV命令の実装を通じ、似た処理に対する実装のコツを解説しました。また、頻繁に必要となるであろうイベントの設計について一つの指針を提示しました。今回の記事を通じて、どのようにオブジェクトの設計を考え、どのように実装するのかを感じていただければ幸いです。
次回は今までの成果を試すアプリケーションを作ります。今までの連載の総決算ですので皆様に楽しんでいただけるかと思います。お楽しみに。