SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

VB.NETで学ぶ機械語の基礎

VB.NETで仮想CPUを作ろう (7) - ADD命令実装

VB.NETで学ぶ機械語の基礎 第7回

  • X ポスト
  • このエントリーをはてなブックマークに追加

テストドライバ側の変更

 まずはMoveDataButton_Clickメソッドの内容を三分割して、他の機械語命令を指定しやすくします。

'指定された命令と対象レジスタから必要なバイナリ決定しその値を返す
Private Function GetCmmandAndRegisterBinay(ByRef binary() As Byte) As Boolean
    Try
        binary(0) = IntelCpu.GetBinary(CmdCombo.SelectedIndex, RegisterCombo.SelectedIndex)
    Catch ae As ArgumentException
        MessageBox.Show(ae.Message, _
            "エラー", _
            MessageBoxButtons.OK, MessageBoxIcon.Error)
        Return False
    End Try
    Return True
End Function

'レジスタのビット数に応じてコピーする値を用意する
Private Function GetValueBinary(ByRef binary() As Byte) As Boolean
    Dim regName As RegisterName = RegisterCombo.SelectedIndex
    'レジスタのビット数に応じてコピーする値を用意する
    If regName < RegisterName.AH Then
        ReDim Preserve binary(4)
        Dim value As UInteger

        'エラーチェック
        If regName < RegisterName.AX Then
            If UInteger.TryParse(ValueText.Text, value) = False Then
                MessageBox.Show("0~" & UInteger.MaxValue.ToString() & "までの数値を入力してください。", _
                     "入力エラー", _
                     MessageBoxButtons.OK, _
                     MessageBoxIcon.Error)
                ValueText.Focus()
                Return False
            End If
        Else
            If UShort.TryParse(ValueText.Text, value) = False Then
                MessageBox.Show("0~" & UShort.MaxValue.ToString() & "までの数値を入力してください。", _
                "入力エラー", _
                MessageBoxButtons.OK, _
                MessageBoxIcon.Error)
                ValueText.Focus()
                Return False
            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(ValueText.Text, value) = True Then
            binary(1) = value
        Else
            MessageBox.Show("0~" & Byte.MaxValue.ToString() & "までの数値を入力してください。", _
                "入力エラー", _
                MessageBoxButtons.OK, _
                MessageBoxIcon.Error)
            ValueText.Focus()
            Return False
        End If
    End If
    Return True
End Function

'指定された命令を実行する
Private Sub ExecuteCommand(ByVal binary() As Byte)
    Me.cpu.ReadBinary(binary)
    Me.cpu.AnalyzeBinary()
    Me.cpu.ExecuteCommand()
End Sub

 処理そのものは前回とほとんど変わりませんので説明は割愛します。

 次に、画面構成そのものを下記の図のように変えます。

画面構成
画面構成
※注
 実際の実行画面とは異なる場合があります。

 各コントロールのプロパティ値は、本稿に添付してあるサンプルプログラムを参考にしてください。

 ここからテストドライバの本格的な改造が始まります。以前はMOVE命令専用だったコマンドボタンの名前を「CmdExeButton」に変え、そのクリック命令を変更します。コードは次のとおりです。

'指定された機械語を実行する
Private Sub CmdExeButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdExeButton.Click
    Dim binary(1) As Byte

    '指定された命令を実行する
    If Me.GetCmmandAndRegisterBinay(binary) = False Then
        Return
    End If
    If Me.GetValueBinary(binary) = True Then
        Me.ExecuteCommand(binary)

        '情報欄を更新する
        Select Case CmdCombo.SelectedIndex
            Case CommandName.Mov
                If RegisterCombo.SelectedIndex = RegisterName.EAX Then
                    ResultLabel.Text = "値が" & EaxValueLabel.Text & "に初期化されました。"
                    EaxValueLabel.Tag = EaxValueLabel.Text
                    AlValueLabel.Tag = Me.before.ValueLowByte.ToString()
                ElseIf RegisterCombo.SelectedIndex = RegisterName.AL Then
                    ResultLabel.Text = "値が" & AlValueLabel.Text & "に初期化されました。"
                    AlValueLabel.Tag = AlValueLabel.Text
                End If
            Case CommandName.Add
                If RegisterCombo.SelectedIndex = RegisterName.EAX Then
                    ResultLabel.Text = EaxValueLabel.Tag.ToString() & _
                        " + " & _
                        UInteger.Parse(ValueText.Text).ToString("N", Me.format) & _
                        " = " & EaxValueLabel.Text
                    EaxValueLabel.Tag = EaxValueLabel.Text
                    AlValueLabel.Tag = Me.before.ValueLowByte.ToString()
                ElseIf RegisterCombo.SelectedIndex = RegisterName.AL Then
                    ResultLabel.Text = AlValueLabel.Tag.ToString() & _
                        " + " & _
                        UInteger.Parse(ValueText.Text).ToString() & _
                        " = " & AlValueLabel.Text
                    AlValueLabel.Tag = AlValueLabel.Text
                End If
        End Select
    End If
End Sub

 コードの量は多いのですが、簡単なことしかしていません。目的は機械語を実行することですから、GetCmmandAndRegisterBinayメソッドとGetValueBinaryメソッドの2つを、例外が起こっていないか確認しながらExecuteCommandメソッドを実行しているだけです。

 あとは、レジスタだけでは計算結果が分かりにくいので「情報欄」を追加し、そこに

 「以前の値」+「指定した値」=計算結果

 を表示しているだけです。ただし、以前の値を保存する方法が少し難しいので説明しておきます。以前の値を保持する場所は「対応するラベルのTagプロパティ」です。まずは初期値から保存しています。

Private Sub TestForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  'レジスタの初期値を保存
    EaxValueLabel.Tag = EaxValueLabel.Text
    AlValueLabel.Tag = Me.before.ValueLowByte.ToString()
End Sub
※注
 レジスタの初期値を保存する処理以外は省略しています。

 さらに、各命令でも保存しています。

'指定された機械語を実行する
Private Sub CmdExeButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdExeButton.Click
    '情報欄を更新する
    Select Case CmdCombo.SelectedIndex
        Case CommandName.Mov
            If RegisterCombo.SelectedIndex = RegisterName.EAX Then
                ResultLabel.Text = "値が" & EaxValueLabel.Text & "に初期化されました。"
                EaxValueLabel.Tag = EaxValueLabel.Text
                AlValueLabel.Tag = Me.before.ValueLowByte.ToString()
            ElseIf RegisterCombo.SelectedIndex = RegisterName.AL Then
                ResultLabel.Text = "値が" & AlValueLabel.Text & "に初期化されました。"
                AlValueLabel.Tag = AlValueLabel.Text '←この部分
            End If
End Sub
※注
 注目するべき処理以外は省略しています。

 これだけでは不十分なので、レジスタの値が変更されたタイミングでも保存しています。

Private Sub RegisterValueChanged(ByVal sender As Object, ByVal e As RegisterValueChangedEventArgs)

    '以前の値を保持する変数へ最新値を保存
    Me.before = New Register(e.Value.ValueU32)
    
End Sub
※注
 注目するべき処理以外は省略しています。

 この処理はレジスタの最新値がCmdExeButton_Clickメソッド実行後は「過去の値」になるのことを利用しています。このように保存しておけば、今度CmdExeButton_Clickメソッド内の処理で適切なラベルのTagプロパティで以前の値として保存できます。

 これでテストドライバの変更作業も終わりです。実際に動かしてCPUの動きを目で確認してください。例えば、ALレジスタの値が255を超えた場合どうなるのかを試してください。その際、ADD命令は「ALレジスタとEAXレジスタしか指定できない」ことに注意してください。

まとめ

 いかがでしょうか? 筆者としては機械語を扱っているという感覚がどんどん強まっています。読者の方々にも同じ感覚を味わってもらえれば幸いです。

 今回は、仮想CPUであるという利点を強調するために、情報を加工してわかりやすく表示する方法を示しました。これは現実のCPUには出来ない芸当です。仮想としての利点は色々ありますが、情報が柔軟に加工出来るのが利点です。その利点を利用して、CPUを理解する一助になればと願っています。

 次回はSUB命令を実装する予定です。おたのしみに。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
VB.NETで学ぶ機械語の基礎連載記事一覧

もっと読む

この記事の著者

インドリ(インドリ)

分析・設計・実装なんでもありのフリーエンジニア。ブログ「無差別に技術をついばむ鳥(http://indori.blog32.fc2.com/)」の作者です。アドバイザーをしたり、システム開発したり、情報処理技術を研究したりと色々しています。座右の銘は温故知新で、新旧関係なく必要だと考えたものは全て学...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/2895 2010/04/27 12:01

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング