SHOEISHA iD

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

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

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

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

VB.NETで仮想CPUを作ろう (6) - MOV命令の実装

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

ExecuteCommandメソッドの変更点

 まずはコードを見てください。

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

 このコードは大変簡単です。あらかじめAnalyzeBinaryメソッドでバイナリを解析し、実行するべき命令をcmdsキューに格納しているので、それを一つ一つ取り出して適切な命令を実行するだけです。

 最後にMov命令について説明します。

Mov命令とレジスタの初期値について

 「Mov命令」とは、レジスタに任意の即値(132などの定数)をコピーしたり、メモリからレジスタに値をコピーしたりする命令です。この命令は必須です。何故かと言うと、実際のレジスタは初期状態に何の値が入っているかわからないからです。初期値を設定しないでレジスタを使用した時の動作はIntel社が保障していません。

 より正確にシミュレートするために、まずはレジスタの初期値を実装します。先述のとおり、レジスタの初期値は何が入っているか分からないので、IntelCpuオブジェクトのコンストラクタで、各レジスタの値をランダムに設定することにします。

'コンストラクタ
Sub New()

    '必要なキューを初期化
    binarys = New Queue(Of Byte)
    cmds = New Queue(Of OpeCode)

    'ランダム値生成オブジェクトを準備
    Dim mask As ULong = CULng(UInteger.MaxValue)
    Dim seed As Integer = CInt((DateTime.Now.Ticks And mask) >> 1)
    Dim rand As Random = New Random(seed)

    'レジスタの値をランダムに設定
    Me.EAX = rand.Next(0, Integer.MaxValue)
    Me.EBX = rand.Next(0, Integer.MaxValue)
    Me.ECX = rand.Next(0, Integer.MaxValue)
    Me.EDX = rand.Next(0, Integer.MaxValue)

End Sub

 キューの初期化部分は前回実装したので割愛し、ランダムな値を生成するオブジェクトを準備する部分について説明します。

 Randomオブジェクトはランダム値を生成するためのオブジェクトです。しかし、規定コンストラクタの

Dim rand As Random = New Random()

 では、ある程度生成される数値にパターンができてしまいます。ですから、

Dim rand As Random = New Random(seed)

 とランダム値を生成する基となる値「シード値」を指定する必要があります。もちろんこのシード値は定数では意味がなく、実行のたびに変化する値が必要となります。この場合、現在の時刻を表すDateTime.Now.Ticksプロパティが適任です。

 しかし、このプロパティの値はLong型で、Randomのコンストラクタが必要としている型はIntegerなので、そのままではオーバーフロー(限界値を超えている状態)になってしまいます。ですから、上位32ビットを無視するようにビット毎のAND論理和を行い、最後に1ビット算術右シフトすることによりIntegerの範囲内でシードを生成しています。

 ここまでくれば後は各レジスタに値を設定するだけです。しかもすべてのレジスタに設定する必要はありません。その理由は、レジスタが入れ子状態だからです。32ビットレジスタの値を設定すれば、16ビットのレジスタと8ビットのレジスタは結果的に値が変わりますので、いちいち設定する必要がないのです。

 これでレジスタの初期値にランダム値を設定するプログラムは完成しました。後はテストドライバの開始時にその値を表示するだけです。テストドライバのロードイベントに次のプログラムを追加してください。

前回実装した部分は非表示
Private Sub TestForm_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load

    'レジスタの初期値を表示
    Me.ShowEaxRegisters(New Register(cpu.EAX))
    Me.ShowEbxRegisters(New Register(cpu.EBX))
    Me.ShowEcxRegisters(New Register(cpu.ECX))
    Me.ShowEdxRegisters(New Register(cpu.EDX))

End Sub

 各レジスタの値がランダム値になっているかチェックするために、テストドライバを実行してください。偶然に0になるレジスタもあるかもしれませんが、各レジスタの値がランダムに設定されている筈です。もし何度実行してもレジスタの値が0と表示される時は、どこかが間違っていますので、もう一度この記事を読みながら自分のプログラムを再度チェックしてください。もしどうしても分からない場合は、サンプルプログラムと自分のプログラムを見比べてください。

 ここまできたらすべての準備は完了です。いよいよMov命令の実装ができます。

次のページ
Mov命令の実装

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

VB.NETで学ぶ機械語の基礎連載記事一覧

もっと読む

この記事の著者

インドリ(インドリ)

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

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

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

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2880 2010/04/27 12:02

イベント

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

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

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

メールバックナンバー