結果の表示とイベント設計
DIV命令の実装が終わりDIV命令をテストドライバで実行できるようになりました。しかしながら、その結果を表示する部分がありません。それにMUL命令についても結果が表示されていません。この理由は、筆者がイベントの設計を変えようと考えていたからです。
現在はRegisterValueChanged
メソッドで全て対応しておりますが、本来イベントは一つの処理をする方が望ましいです。つまり、IntelCpu
を利用する側が工夫するのではなく、IntelCpu
側で利用する側の利便性を図るのがいいのです。そこで筆者は新しいイベントをいくつか考えました。
イベント設計で重要なことは「選択性」と「柔軟性」です。もしIntelCpu
が何らかのイベントを前提として動作するのならば、利用する側の負担が大きすぎます。それに、何らかの前提を設けてしまうとIntelCpu
が非常に使い辛いものとなります。その2つの性質を実現する為には.NETのオブジェクト指向機能をフル活用します。
イベントを設計するに当たって今まで実装してきた命令を改めて考えてみました。その結果MOV命令と算術命令に分かれていることに気づきました。そこで筆者は2つのイベントオブジェクトを作りました。
Public Class ExecuteCommandEventArgs Inherits EventArgs '実行されたコマンドの名前 Private m_name As CommandName Public Overridable ReadOnly Property Name() As CommandName Get Return m_name End Get End Property '必ず実行した命令を指定してインスタンスを生成するようにします Public Sub New(ByVal name As CommandName) Me.m_name = name End Sub End Class Public Class MovCommandEndEventArgs Inherits ExecuteCommandEventArgs '変更後の値 Private m_value As UInteger Public Property Value() As UInteger Get Return Me.m_value End Get Set(ByVal value As UInteger) Me.m_value = value End Set End Property '必ず値を指定して、インスタンスを生成するようにします。 Public Sub New(ByVal value As UInteger) MyBase.New(CommandName.Mov) Me.m_value = value End Sub End Class '算術系命令が終了したことを表すイベントの情報 Public Class CalculateCommandEndEventArgs Inherits ExecuteCommandEventArgs '変更後の値 Private m_after As ULong Public Property AfterValue() As ULong Get Return Me.m_after End Get Set(ByVal value As ULong) Me.m_after = value End Set End Property '指定した値 Private m_value As ULong Public Property Value() As ULong Get Return Me.m_value End Get Set(ByVal value As ULong) Me.m_value = value End Set End Property '変更前の値 Private m_before As ULong Public Property BeforeValue() As ULong Get Return Me.m_before End Get Set(ByVal value As ULong) Me.m_before = value End Set End Property '符号 Private m_sign As Char Public ReadOnly Property Sign() As Char Get Return Me.m_sign End Get End Property '必ず、実行した命令・更新前の値・指定する値(加算値など)・更新後の値の四つの情報を指定して、インスタンスを生成するようにします。 Public Sub New(ByVal name As CommandName, ByVal beforeValue As ULong, ByVal value As ULong, ByVal afterValue As ULong) MyBase.New(name) Me.m_after = afterValue Me.m_value = value Me.m_before = beforeValue Select Case name Case CommandName.Add Me.m_sign = "+" Case CommandName.Inc Me.m_sign = "+" Case CommandName.Subtract Me.m_sign = "-" Case CommandName.Dec Me.m_sign = "-" Case CommandName.Mul Me.m_sign = "*" Case CommandName.Div Me.m_sign = "/" End Select End Sub End Class 'DIV命令が終了したことを表すイベントの情報 Public Class DivCommandEventArgs Inherits CalculateCommandEndEventArgs '変更前の剰余 Private m_beforeRemainder As UInteger Public Property BeforeRemainder() As UInteger Get Return m_beforeRemainder End Get Set(ByVal value As UInteger) m_beforeRemainder = value End Set End Property '変更後の剰余 Private m_afterRemainder As UInteger Public Property AfterRemainder() As UInteger Get Return m_afterRemainder End Get Set(ByVal value As UInteger) m_afterRemainder = value End Set End Property '必ず実行した命令を指定してインスタンスを生成するようにします Public Sub New(ByVal name As CommandName, _ ByVal beforeValue As ULong, ByVal value As ULong, ByVal afterValue As ULong, _ ByVal beforeRemainder As UInteger, ByVal afterRemainder As UInteger) MyBase.New(CommandName.Div, beforeValue, value, afterValue) Me.m_beforeRemainder = beforeRemainder Me.m_afterRemainder = afterRemainder End Sub End Class '汎用の機械語命令実行完了イベント Public Event ExecuteCommandEnd(ByVal sender As Object, ByVal e As ExecuteCommandEventArgs) '機械語命令の実行が完了したことを通知する Private Sub OnExecuteCommandEnd(ByVal name As CommandName) Dim e As ExecuteCommandEventArgs = New ExecuteCommandEventArgs(name) RaiseEvent ExecuteCommandEnd(Me, e) End Sub 'MOV命令実行完了イベント Public Event MoveCommandEnd(ByVal sender As Object, ByVal e As MovCommandEndEventArgs) 'MOV命令の実行が完了したことを通知する Private Sub OnMovCommandEnd(ByVal value As UInteger) Dim e As MovCommandEndEventArgs = New MovCommandEndEventArgs(value) RaiseEvent MoveCommandEnd(Me, e) End Sub '計算命令実行完了イベント Public Event CalculateCommandEnd(ByVal sender As Object, ByVal e As CalculateCommandEndEventArgs) '計算命令の実行が完了したことを通知する Private Sub OnCalculateExecuteCommandEnd(ByVal name As CommandName, ByVal beforeValue As ULong, ByVal value As ULong, ByVal afterValue As ULong) Dim e As CalculateCommandEndEventArgs = New CalculateCommandEndEventArgs(name, beforeValue, value, afterValue) RaiseEvent CalculateCommandEnd(Me, e) End Sub 'DIV命令の実行が完了したことを通知する Private Sub OnDivExecuteCommandEnd(ByVal name As CommandName, _ ByVal beforeQuotient As UInteger, ByVal value As ULong, ByVal afterQuotient As UInteger, _ ByVal beforeRemainder As UInteger, ByVal afterRemainder As UInteger) Dim e As DivCommandEventArgs = New DivCommandEventArgs(name, beforeQuotient, value, afterQuotient, beforeRemainder, afterRemainder) RaiseEvent CalculateCommandEnd(Me, e) End Sub
まずこれらのオブジェクトを実装するに当たって気をつけたことは「利用側にレジスタを意識させない」ということです。今まではRegisterValueChanged
イベントでレジスタの役割や実行した命令などを考えつつ実装しました。しかし、本来オブジェクトはそれを利用する側に前提知識を強いてはなりません。前提知識を強いると生産効率が落ちて、何のためにオブジェクト指向でプログラミングしているのか分からなくなります。
次に考えたのは「共通部分を継承させる」ということです。MOV命令以外は算術系の命令であって、なるべく一つのオブジェクトで処理できるようにしなくてはイベント数が多くなり、利用する側が大変です。そこで、共通概念を考えて算術系のイベントオブジェクトwを実装し、唯一DIV命令は継承オブジェクトを作ることにしました。そうすることで、利用側が柔軟に利用できるようになります。
なお、筆者がExecuteCommandEventArgs
を実装したわけは、「とにかく機械語の実行が終わったタイミングが知りたい」時があると考えたからです。それにIntelCpu
オブジェクトは他にも違う種類のイベントが実装していますから、機械語命令を実行したという共通概念をまとめた方が利便性が高くなると考えたのです。
実際の開発では、こういった判断はそのときのシステムの性質を考えて判断することになります。従って「何でもまとめればいい」というわけでもありません。その使い分けについては経験を積めば判断できるようになります。