SHOEISHA iD

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

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

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

VB.NETで仮想CPUを作ろう (11)
- DIV命令の実装とイベント設計について

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

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

ダウンロード VirtualCPU11.zip (317.2 KB)

DIV命令実装と実行

 これでしばらくDIV命令の実装を行えます。これから筆者のDIV命令の実装例を掲載しますが、読者の方も「DIV命令の説明」の項をよく読んで実装してみてください。

'DIV命令の実装
Private Sub Div(ByVal ope As OpeCode)
    Select Case ope.BitCount
        Case 8
            '値を先に用意
            Dim value As UShort
            If ope.IsHi Then
                value = ope.Value.ValueHighByte
            Else
                value = ope.Value.ValueLowByte
            End If

            '剰余を算出
            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)
        Case 32
            '値を先に用意
            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)
    End Select
End Sub


'解析済みの命令を実行します。
Public Sub ExecuteCommand()
    Dim cmd As OpeCode
    While cmds.Count <> 0
        cmd = cmds.Dequeue()
        Select Case cmd.Name
            '命令を選択して実行
            Case CommandName.Add
                Add(cmd)
            Case CommandName.Subtract
                Subtract(cmd)
            Case CommandName.Inc
                Inc(cmd)
            Case CommandName.Dec
                Dec(cmd)
            Case CommandName.Mov
                Mov(cmd)
            Case CommandName.Mul
                Mul(cmd)
            Case CommandName.Div
                Div(cmd)
        End Select
    End While
End Sub

 ではコードの説明をします。DIV命令の実装ポイントは、「商と剰余を別のレジスタに保存する」点と「計算順序」です。その点さえ気をつければ、今までの命令よりも実装は容易だと思います。

 計算順序は剰余を計算してから商を計算します。その理由は端数処理が簡単になるからです。あらかじめ剰余を計算しておき、その値を引いておくと必ず割り切れますので、端数をどうするのかを気にする必要がなくなります。このようにしておかないと、端数を四捨五入するのか、切り捨てるのか……などのルールを決めなくてはなりません。そのような処理は、CPUではなくアプリケーション側でするべきことなので、端数処理をしないですむように考慮して実装しました。

 以上でIntelCpuオブジェクト視点の修正は終わりです。後はオブジェクトを利用側の視点で修正を行っていきます。

バイナリ取得機能の修正

 ここまでの説明で、IntelCpuオブジェクトの内部ではDIV命令が実行できるようになりました。しかしそれでは、IntelCpuオブジェクトを利用する側がDIV命令を扱えませんので、GetBinaryメソッドを修正しなければなりません。まずは実装例を掲載し、すぐ後で説明を行います。

'指定された命令と対象レジスタから指定するべきバイナリを導出する
Public Shared Function GetBinary(ByVal cmd As CommandName, ByVal reg As RegisterName) As Byte
    Dim result As Byte = 0

    'オペコードマップの行と列の値を決定
    Select Case cmd
        Case CommandName.Mul, CommandName.Div
            result = 15 << 4
            If reg >= RegisterName.EAX And reg <= RegisterName.EDX Then
                result += 7
            ElseIf reg >= RegisterName.AH And reg <= RegisterName.DL Then
                result += 6
            Else
                Throw New ArgumentException("命令" & cmd.ToString() & "は" & _
                    reg.ToString() & "レジスタをサポートしておりません。")
            End If
    End Select

    '結果を返す
    Return result
End Function

 Case部分でMUL命令とDIV命令に同じバイナリを返しています。理由はDIV命令の概要の項で述べたように、MUL命令とDIV命令では同じバイナリ値だからです。もちろんこれでは困りますので、使用側がModR/Mのバイナリを操作して両命令を分けて指定するようにします。その実装方法について事項で述べます。

命令の使い分け

 命令を使い分けるにはCmdExeButton_Clickを修正する必要があります。このメソッドは次の掲載例のように修正します。

'指定された機械語を実行する
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

    '命令長を取得
    Dim length As Integer = IntelCpu.GetCommandLength(Me.CmdCombo.SelectedIndex)

    '命令長が1の場合は値に関するバイナリは必要ない
    If length > 1 Then
        If Me.CmdCombo.SelectedIndex = CommandName.Mul Or Me.CmdCombo.SelectedIndex = CommandName.Div Then
            'ModR/Mのバイナリを取得する
            binary(1) = IntelCpu.GetModRMBinary(Me.CmdCombo.SelectedIndex, _
                CType(Me.RegisterCombo.SelectedIndex, RegisterName))
            Me.ExecuteCommand(binary)
        Else
            If Me.GetValueBinary(binary) = True Then
                Me.ExecuteCommand(binary)
            End If
        End If
    Else
        Me.ExecuteCommand(binary)
    End If
End Sub

 ポイントは

If Me.CmdCombo.SelectedIndex = CommandName.Mul Or Me.CmdCombo.SelectedIndex = CommandName.Div Then
            'ModR/Mのバイナリを取得する
            binary(1) = IntelCpu.GetModRMBinary(Me.CmdCombo.SelectedIndex, _
                CType(Me.RegisterCombo.SelectedIndex, RegisterName))
            Me.ExecuteCommand(binary)

 の部分です。今までの作業によりIntelCpuオブジェクトのGetModRMBinaryメソッドでDIV命令に対処済みなので、呼ぶだけでDIV命令のバイナリを得られます。

 後はCmdComboコントロールの最後にDIVを追加するだけです。これでDIV命令の実行のテストができます。

次のページ
結果の表示とイベント設計

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

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

もっと読む

この記事の著者

インドリ(インドリ)

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

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング