テストドライバ側の対応
テストドライバがまずやるべきことは、INC命令とDEC命令を指定できるようにすることです。もっと具体的に言うと、CmdCombo
コントロールのアイテムにIncとDecを指定せねばなりません。プロパティウインドウでItems
プロパティにIncとDecを追加してください。
次にするべきことは命令の実行結果を表示することです。INCとDEC命令の実行結果を表示するには、RegisterValueChanged
メソッドを変更します。結果を表示するべき命令が増えて、メソッドが読みにくくなってきましたので、今回リファクタリングしてINC命令とDEC命令に対応しました。まずはそのコードを掲載し、後でその内容を説明します。
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 '情報欄を更新する Select Case CmdCombo.SelectedIndex Case CommandName.Mov If Me.RegisterCombo.SelectedIndex = RegisterName.EAX Then ResultLabel.Text = "値が" & e.AfterValue.ValueU32.ToString() & "に初期化されました。" ElseIf Me.RegisterCombo.SelectedIndex = RegisterName.AL Then ResultLabel.Text = "値が" & e.AfterValue.ValueLowByte.ToString() & "に初期化されました。" End If Case CommandName.Add, CommandName.Subtract, CommandName.Inc, CommandName.Dec '符号を設定 Dim sign As String = "" If CmdCombo.SelectedIndex = CommandName.Add OrElse _ CmdCombo.SelectedIndex = CommandName.Inc Then sign = " + " ElseIf CmdCombo.SelectedIndex = CommandName.Subtract OrElse _ CmdCombo.SelectedIndex = CommandName.Dec Then sign = " - " End If '値を設定 Dim value As String = "" If CmdCombo.SelectedIndex = CommandName.Add OrElse _ CmdCombo.SelectedIndex = CommandName.Subtract Then value = UInteger.Parse(ValueText.Text).ToString("N", Me.format) ElseIf CmdCombo.SelectedIndex = CommandName.Inc OrElse _ CmdCombo.SelectedIndex = CommandName.Dec Then value = "1" End If '結果を設定 Dim result As String = "" Select Case e.BitCount Case 32 result = e.AfterValue.ValueU32.ToString() Case 16 result = e.AfterValue.ValueU16.ToString() Case 8 If e.IsHi Then result = e.AfterValue.ValueHighByte.ToString() Else result = e.AfterValue.ValueLowByte.ToString() End If End Select '計算式を表示 ResultLabel.Text = e.BeforeValue.ValueU32.ToString() & _ sign & value & " = " & result End Select End Sub
前回のソースと見比べてください。ずいぶん変わったと思います。しかし、行っていることは前回とあまり変わりませんし、これから丁寧に説明しますので、安心して読み進めてください。
大まかな方針として、筆者は「同じ目的を持ったコードを固める」ことにしました。前回も少しお話しましたが、人間はコードが散らばると理解しにくくなります。それに、まとめて考えた方がコードを理解しやすくなります。ですから、目的ごとにコードを集めました。
その結果、このメソッドのコードは「レジスタの値を反映する」処理と「情報欄を更新する」処理の2つに大別できるようになりました。レジスタの値を反映する処理については解説済みなので、もう一方の「情報欄を更新する」処理を説明します。
この処理はさらに「符号を設定」「値を設定」「結果を設定」「計算式を設定」と4つに分かれています。初心者の方は難しく見えるかもしれませんが、これから書くイメージで捉えれば簡単です。
元の値(BeforeValue) +-などの符号(sign) 値(value)= 結果(result)
先ほど書いた4個の処理は、それぞれの変数の値を決定するだけのものであり、難しいことはしていません。一見複雑に見える処理も、このようにイメージで捉えれば簡単になるケースが実務でも多いので、なるべくコードをイメージの塊で考えるようにしてみてください。そうするとコードを読む力がぐんとアップします。
実行していろいろと試してください。実行すればINC命令とDEC命令が正しく実装されていることが確認できます。しかし、操作勝手に問題があるのが分かると思います。
よりよいテスト
現状のテストドライバでまず気になるのが「値欄」です。INC命令とDEC命令は値が1に固定されているので、値欄に値が入力できる状態では余計な混乱を生みます。まずはその点を改善するために、CmdCombo
コントロールのSelectedIndexChanged
イベントに次にコードを書き込みます。
'選択した命令にあわせて値欄の表示を操作する Private Sub CmdCombo_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdCombo.SelectedIndexChanged If Me.CmdCombo.SelectedIndex = CommandName.Inc OrElse _ Me.CmdCombo.SelectedIndex = CommandName.Dec Then Me.ValueText.Enabled = False Else Me.ValueText.Enabled = True End If End Sub
これでINC命令とDEC命令のテスト時に余計な混乱を生まなくて済みます。一度実行してみてください。INC命令とDEC命令を選択した際には値欄が編集できなくなって、テスト作業が分かりやすくなったことが確認できます。
次に筆者が気になったのは、限界値テストのやりにくさです。限界値テストというのは、システム仕様の最大値を超えた場合どうなるか、最小値未満の値を指定したらどうなるかなどをテストすることです。今回の場合、0の状態でインクリメントしたらどうなるかと、32ビット値の最大値を超えた場合どうなのかをテストしなければなりません。しかし、現状では非常にやりにくいです。そこで、限界値を値入力欄に設定できる用にフォームにメニューを追加しました。
画面を掲載しますのでそれとサンプルコードを参考にしてメニューを追加してください。
そして、追加したメニューのクリックイベントに次のコードをコーディングします。
'最大値を設定する Private Sub MaxValueMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MaxValueMenuItem.Click If Me.RegisterCombo.Text(0) = "E" Then Me.ValueText.Text = UInteger.MaxValue.ToString() ElseIf RegisterCombo.Text(1) = "X" Then Me.ValueText.Text = UShort.MaxValue.ToString() Else Me.ValueText.Text = Byte.MaxValue.ToString() End If End Sub}
これで限界値のテストが行いやすくなりました。このようにテストの際には、素早く正確に行うための準備をしておくことをお勧めします。
まとめ
いかがでしょうか? 今回は仮想CPUを作る上で避けられない命令長の扱いについて解説しました。
また、この記事の読者が実務で活躍することを祈って、限界値テストや実務で培ったコーディングのノウハウを散りばめました。プロとアマの違いは実のところ意外と少なく、心がけ次第でプロにもアマにもなることが伝われば幸いです。
何のプロでもそうだと思うのですが、プロとは「他者への気配り」がその明暗を分けると筆者は思います。お客様に対して親切にするのは勿論のこと、一緒に仕事をする同僚や、未来に自分のコード保守する人まで気を配ることができれば、その人は立派なプロと呼ばれることでしょう。
次回は、今までで一番手強いMUL(乗算)命令の実装を紹介します。この命令を実装することにより、IntelCPUにレジスタが複数あることの意味が見えてくるでしょう。お楽しみに。